그리드 레이아웃에서 제스처 감지 감지 SelectFilterActivity extends Activity implements

fling내 Android 응용 프로그램에서 동작 감지를 원합니다 .

내가 가진 것은 GridLayout9 ImageView초 를 포함 하는 것 입니다 . 소스는 여기에서 찾을 수 있습니다 : Romain Guys ‘s Grid Layout .

내가 가져간 파일은 Romain Guy의 Photostream 응용 프로그램 에서 가져온 것으로 약간만 조정되었습니다.

간단한 클릭 상황에서는 내가 추가하는 onClickListener각각 을 구현 ImageView하는 기본으로 설정하면 됩니다 . 를 인식하는 것을 구현하는 것은 무한히 더 복잡해 보입니다 . 나는 이것이 스팬 될 수 있기 때문이라고 생각 합니까?activityView.OnClickListenerflingviews

  • 내 활동이 구현되면
    내가 추가 한보 기 또는 보기 OnGestureListener의 제스처 리스너로 설정하는 방법을 모르겠습니다 .GridImage

    public class SelectFilterActivity extends Activity implements
       View.OnClickListener, OnGestureListener { ...
    
  • 내 활동이 구현되면
    메소드 OnTouchListener가 없습니다
    (플링이 주목할 만한지를 결정할 수있는 매개 변수로 두 가지 이벤트가 있습니다).onFlingoverride

    public class SelectFilterActivity extends Activity implements
        View.OnClickListener, OnTouchListener { ...
    
  • 내가 확장 View과 같이 custom을 만들면 활동이 뷰에서 발생 했음을 알리는 방법을 모르겠습니다 . 어쨌든, 나는 이것을 시도했지만 화면을 터치했을 때 메소드가 호출되지 않았습니다.GestureImageViewImageViewfling

나는 실제로 여러 관점에서 작동하는 구체적인 예가 필요합니다. 무엇을 언제 어떻게해야 listener합니까? 클릭 한 번도 감지 할 수 있어야합니다.

// Gesture detection
mGestureDetector = new GestureDetector(this, new GestureDetector.SimpleOnGestureListener() {

    public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY) {
        int dx = (int) (e2.getX() - e1.getX());
        // don't accept the fling if it's too short
        // as it may conflict with a button push
        if (Math.abs(dx) > MAJOR_MOVE && Math.abs(velocityX) > Math.absvelocityY)) {
            if (velocityX > 0) {
                moveRight();
            } else {
                moveLeft();
            }
            return true;
        } else {
            return false;
        }
    }
});

플링을 캡처하기 위해 화면 상단에 투명 뷰를 배치 할 수 있습니까?

inflateXML에서 내 자식 이미지 뷰를 선택하지 않으면 GestureDetector생성자의 새 하위 클래스에 생성자 매개 변수를 전달할 ImageView수 있습니까?

이것은 SelectFilterActivity (Adapted from photostream)fling 감지 기능을 작동 시키려는 매우 간단한 활동입니다 .

나는이 소스를보고있다 :

지금까지 아무것도 효과가 없었으며 포인터를 원했습니다.



답변

Code Shogun 덕분에 코드 가 내 상황에 맞게 조정되었습니다.

OnClickListener평소와 같이 활동을 구현하십시오 .

public class SelectFilterActivity extends Activity implements OnClickListener {

  private static final int SWIPE_MIN_DISTANCE = 120;
  private static final int SWIPE_MAX_OFF_PATH = 250;
  private static final int SWIPE_THRESHOLD_VELOCITY = 200;
  private GestureDetector gestureDetector;
  View.OnTouchListener gestureListener;

  @Override
  protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);

    /* ... */

    // Gesture detection
    gestureDetector = new GestureDetector(this, new MyGestureDetector());
    gestureListener = new View.OnTouchListener() {
      public boolean onTouch(View v, MotionEvent event) {
        return gestureDetector.onTouchEvent(event);
      }
    };

  }

  class MyGestureDetector extends SimpleOnGestureListener {
    @Override
    public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY) {
      try {
        if (Math.abs(e1.getY() - e2.getY()) > SWIPE_MAX_OFF_PATH)
          return false;
        // right to left swipe
        if(e1.getX() - e2.getX() > SWIPE_MIN_DISTANCE && Math.abs(velocityX) > SWIPE_THRESHOLD_VELOCITY) {
          Toast.makeText(SelectFilterActivity.this, "Left Swipe", Toast.LENGTH_SHORT).show();
        } else if (e2.getX() - e1.getX() > SWIPE_MIN_DISTANCE && Math.abs(velocityX) > SWIPE_THRESHOLD_VELOCITY) {
          Toast.makeText(SelectFilterActivity.this, "Right Swipe", Toast.LENGTH_SHORT).show();
        }
      } catch (Exception e) {
         // nothing
      }
      return false;
    }

    @Override
    public boolean onDown(MotionEvent e) {
      return true;
    }
  }
}

기본 레이아웃에 추가 한 모든보기에 제스처 리스너를 연결하십시오.

// Do this for each view added to the grid
imageView.setOnClickListener(SelectFilterActivity.this); 
imageView.setOnTouchListener(gestureListener);

onClick(View v)활동과 onFling제스처 리스너 모두에서 재정의 된 메소드에 도달하면 경외심을 가지십시오 .

public void onClick(View v) {
  Filter f = (Filter) v.getTag();
  FilterFullscreenActivity.show(this, input, f);
}

포스트 ‘fling’댄스는 선택 사항이지만 권장됩니다.


답변

위의 답변 중 하나는 다른 픽셀 밀도를 다루는 것을 언급하지만 손으로 ​​스 와이프 매개 변수를 계산할 것을 제안합니다. ViewConfigurationclass를 사용하여 시스템에서 실제로 스케일되고 합리적인 값을 얻을 수 있습니다 .

final ViewConfiguration vc = ViewConfiguration.get(getContext());
final int swipeMinDistance = vc.getScaledPagingTouchSlop();
final int swipeThresholdVelocity = vc.getScaledMinimumFlingVelocity();
final int swipeMaxOffPath = vc.getScaledTouchSlop();
// (there is also vc.getScaledMaximumFlingVelocity() one could check against)

이 값을 사용하면 응용 프로그램과 나머지 시스템간에 “느낌”느낌이 더 일관된 것으로 나타났습니다.


답변

나는 그것을 조금 다르게하고 구현하는 추가 검출기 클래스를 작성했습니다. View.onTouchListener

onCreate간단히 다음과 같이 가장 낮은 레이아웃에 추가하십시오.

ActivitySwipeDetector activitySwipeDetector = new ActivitySwipeDetector(this);
lowestLayout = (RelativeLayout)this.findViewById(R.id.lowestLayout);
lowestLayout.setOnTouchListener(activitySwipeDetector);

여기서 id.lowestLayout은 레이아웃 계층 구조에서 가장 낮은 뷰의 id.xxx이고 가장 낮은 레이아웃은 RelativeLayout으로 선언됩니다.

그리고 실제 활동 스 와이프 탐지기 클래스가 있습니다.

public class ActivitySwipeDetector implements View.OnTouchListener {

static final String logTag = "ActivitySwipeDetector";
private Activity activity;
static final int MIN_DISTANCE = 100;
private float downX, downY, upX, upY;

public ActivitySwipeDetector(Activity activity){
    this.activity = activity;
}

public void onRightSwipe(){
    Log.i(logTag, "RightToLeftSwipe!");
    activity.doSomething();
}

public void onLeftSwipe(){
    Log.i(logTag, "LeftToRightSwipe!");
    activity.doSomething();
}

public void onDownSwipe(){
    Log.i(logTag, "onTopToBottomSwipe!");
    activity.doSomething();
}

public void onUpSwipe(){
    Log.i(logTag, "onBottomToTopSwipe!");
    activity.doSomething();
}

public boolean onTouch(View v, MotionEvent event) {
    switch(event.getAction()){
        case MotionEvent.ACTION_DOWN: {
            downX = event.getX();
            downY = event.getY();
            return true;
        }
        case MotionEvent.ACTION_UP: {
            upX = event.getX();
            upY = event.getY();

            float deltaX = downX - upX;
            float deltaY = downY - upY;

       // swipe horizontal?
        if(Math.abs(deltaX) > Math.abs(deltaY))
        {
            if(Math.abs(deltaX) > MIN_DISTANCE){
                // left or right
                if(deltaX > 0) { this.onRightSwipe(); return true; }
                if(deltaX < 0) { this.onLeftSwipe(); return true; }
            }
            else {
                    Log.i(logTag, "Horizontal Swipe was only " + Math.abs(deltaX) + " long, need at least " + MIN_DISTANCE);
                    return false; // We don't consume the event
            }
        }
        // swipe vertical?
        else
        {
            if(Math.abs(deltaY) > MIN_DISTANCE){
                // top or down
                if(deltaY < 0) { this.onDownSwipe(); return true; }
                if(deltaY > 0) { this.onUpSwipe(); return true; }
            }
            else {
                    Log.i(logTag, "Vertical Swipe was only " + Math.abs(deltaX) + " long, need at least " + MIN_DISTANCE);
                    return false; // We don't consume the event
            }
        }

            return true;
        }
    }
    return false;
}

}

정말 잘 작동합니다!


답변

Thomas Fankhauser의 솔루션을 약간 수정하고 수리했습니다.

전체 시스템은 SwipeInterfaceActivitySwipeDetector의 두 파일로 구성됩니다.


SwipeInterface.java

import android.view.View;

public interface SwipeInterface {

    public void bottom2top(View v);

    public void left2right(View v);

    public void right2left(View v);

    public void top2bottom(View v);

}

탐지기

import android.util.Log;
import android.view.MotionEvent;
import android.view.View;

public class ActivitySwipeDetector implements View.OnTouchListener {

    static final String logTag = "ActivitySwipeDetector";
    private SwipeInterface activity;
    static final int MIN_DISTANCE = 100;
    private float downX, downY, upX, upY;

    public ActivitySwipeDetector(SwipeInterface activity){
        this.activity = activity;
    }

    public void onRightToLeftSwipe(View v){
        Log.i(logTag, "RightToLeftSwipe!");
        activity.right2left(v);
    }

    public void onLeftToRightSwipe(View v){
        Log.i(logTag, "LeftToRightSwipe!");
        activity.left2right(v);
    }

    public void onTopToBottomSwipe(View v){
        Log.i(logTag, "onTopToBottomSwipe!");
        activity.top2bottom(v);
    }

    public void onBottomToTopSwipe(View v){
        Log.i(logTag, "onBottomToTopSwipe!");
        activity.bottom2top(v);
    }

    public boolean onTouch(View v, MotionEvent event) {
        switch(event.getAction()){
        case MotionEvent.ACTION_DOWN: {
            downX = event.getX();
            downY = event.getY();
            return true;
        }
        case MotionEvent.ACTION_UP: {
            upX = event.getX();
            upY = event.getY();

            float deltaX = downX - upX;
            float deltaY = downY - upY;

            // swipe horizontal?
            if(Math.abs(deltaX) > MIN_DISTANCE){
                // left or right
                if(deltaX < 0) { this.onLeftToRightSwipe(v); return true; }
                if(deltaX > 0) { this.onRightToLeftSwipe(v); return true; }
            }
            else {
                Log.i(logTag, "Swipe was only " + Math.abs(deltaX) + " long, need at least " + MIN_DISTANCE);
            }

            // swipe vertical?
            if(Math.abs(deltaY) > MIN_DISTANCE){
                // top or down
                if(deltaY < 0) { this.onTopToBottomSwipe(v); return true; }
                if(deltaY > 0) { this.onBottomToTopSwipe(v); return true; }
            }
            else {
                Log.i(logTag, "Swipe was only " + Math.abs(deltaX) + " long, need at least " + MIN_DISTANCE);
                v.performClick();
            }
        }
        }
        return false;
    }

}

다음과 같이 사용됩니다.

ActivitySwipeDetector swipe = new ActivitySwipeDetector(this);
LinearLayout swipe_layout = (LinearLayout) findViewById(R.id.swipe_layout);
swipe_layout.setOnTouchListener(swipe);

그리고 구현시 SwipeInterface의Activity 메소드를 구현해야 하며 Swipe 이벤트 가 호출 된 뷰를 찾을 수 있습니다 .

@Override
public void left2right(View v) {
    switch(v.getId()){
        case R.id.swipe_layout:
            // do your stuff here
        break;
    }
}

답변

위의 스 와이프 동작 탐지기 코드는 매우 유용합니다! 그러나 (REL_SWIPE)절대 값이 아닌 다음 상대 값을 사용하여이 솔루션 밀도를 불가지론 적으로 만들 수 있습니다.(SWIPE_)

DisplayMetrics dm = getResources().getDisplayMetrics();

int REL_SWIPE_MIN_DISTANCE = (int)(SWIPE_MIN_DISTANCE * dm.densityDpi / 160.0f);
int REL_SWIPE_MAX_OFF_PATH = (int)(SWIPE_MAX_OFF_PATH * dm.densityDpi / 160.0f);
int REL_SWIPE_THRESHOLD_VELOCITY = (int)(SWIPE_THRESHOLD_VELOCITY * dm.densityDpi / 160.0f);

답변

Thomas FankhauserMarek Sebera가 제안한 내 솔루션 버전 (수직 스 와이프는 처리하지 않음) :

SwipeInterface.java

import android.view.View;

public interface SwipeInterface {

    public void onLeftToRight(View v);

    public void onRightToLeft(View v);
}

ActivitySwipeDetector.java

import android.content.Context;
import android.util.DisplayMetrics;
import android.util.Log;
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewConfiguration;

public class ActivitySwipeDetector implements View.OnTouchListener {

    static final String logTag = "ActivitySwipeDetector";
    private SwipeInterface activity;
    private float downX, downY;
    private long timeDown;
    private final float MIN_DISTANCE;
    private final int VELOCITY;
    private final float MAX_OFF_PATH;

    public ActivitySwipeDetector(Context context, SwipeInterface activity){
        this.activity = activity;
        final ViewConfiguration vc = ViewConfiguration.get(context);
        DisplayMetrics dm = context.getResources().getDisplayMetrics();
        MIN_DISTANCE = vc.getScaledPagingTouchSlop() * dm.density;
        VELOCITY = vc.getScaledMinimumFlingVelocity();
        MAX_OFF_PATH = MIN_DISTANCE * 2;
    }

    public void onRightToLeftSwipe(View v){
        Log.i(logTag, "RightToLeftSwipe!");
        activity.onRightToLeft(v);
    }

    public void onLeftToRightSwipe(View v){
        Log.i(logTag, "LeftToRightSwipe!");
        activity.onLeftToRight(v);
    }

    public boolean onTouch(View v, MotionEvent event) {
        switch(event.getAction()){
        case MotionEvent.ACTION_DOWN: {
            Log.d("onTouch", "ACTION_DOWN");
            timeDown = System.currentTimeMillis();
            downX = event.getX();
            downY = event.getY();
            return true;
        }
        case MotionEvent.ACTION_UP: {
            Log.d("onTouch", "ACTION_UP");
            long timeUp = System.currentTimeMillis();
            float upX = event.getX();
            float upY = event.getY();

            float deltaX = downX - upX;
            float absDeltaX = Math.abs(deltaX);
            float deltaY = downY - upY;
            float absDeltaY = Math.abs(deltaY);

            long time = timeUp - timeDown;

            if (absDeltaY > MAX_OFF_PATH) {
                Log.i(logTag, String.format("absDeltaY=%.2f, MAX_OFF_PATH=%.2f", absDeltaY, MAX_OFF_PATH));
                return v.performClick();
            }

            final long M_SEC = 1000;
            if (absDeltaX > MIN_DISTANCE && absDeltaX > time * VELOCITY / M_SEC) {
                if(deltaX < 0) { this.onLeftToRightSwipe(v); return true; }
                if(deltaX > 0) { this.onRightToLeftSwipe(v); return true; }
            } else {
                Log.i(logTag, String.format("absDeltaX=%.2f, MIN_DISTANCE=%.2f, absDeltaX > MIN_DISTANCE=%b", absDeltaX, MIN_DISTANCE, (absDeltaX > MIN_DISTANCE)));
                Log.i(logTag, String.format("absDeltaX=%.2f, time=%d, VELOCITY=%d, time*VELOCITY/M_SEC=%d, absDeltaX > time * VELOCITY / M_SEC=%b", absDeltaX, time, VELOCITY, time * VELOCITY / M_SEC, (absDeltaX > time * VELOCITY / M_SEC)));
            }

        }
        }
        return false;
    }

}

답변

이 질문은 일종의 구식이며 2011 년 7 월 Google 은 Android 1.6 이상에서 작동 하는 호환성 패키지 개정 3) 을 발표했습니다 ViewPager. 이 GestureListener질문에 대한 답변은 Android에서 매우 우아하지 않습니다. Android 갤러리에서 사진을 전환하거나 새로운 Play Market 앱에서보기를 전환하는 데 사용되는 코드를 찾고 있다면 분명히 코드 ViewPager입니다.

자세한 내용은 다음 링크를 참조하십시오.