Phát hiện cử chỉ fling trên bố trí lưới


1106

Tôi muốn nhận được flingphát hiện cử chỉ làm việc trong ứng dụng Android của mình.

Những gì tôi có là một GridLayoutcái chứa 9 ImageViews. Nguồn có thể được tìm thấy ở đây: Bố cục lưới của Romain Guys .

Tập tin tôi lấy là từ ứng dụng Photostream của Romain Guy và chỉ được điều chỉnh một chút.

Đối với tình huống nhấp chuột đơn giản, tôi chỉ cần đặt onClickListenercho mỗi ImageViewtôi thêm là chính activitymà thực hiện View.OnClickListener. Dường như vô cùng phức tạp hơn để thực hiện một cái gì đó nhận ra a fling. Tôi đoán điều này là bởi vì nó có thể kéo dài views?

  • Nếu hoạt động của tôi thực hiện, OnGestureListenertôi không biết làm thế nào để đặt nó làm người nghe cử chỉ cho Gridhoặc các Imagequan điểm mà tôi thêm.

    public class SelectFilterActivity extends Activity implements
       View.OnClickListener, OnGestureListener { ...
  • Nếu hoạt động của tôi thực hiện OnTouchListenerthì tôi không có onFlingphương pháp nào override(nó có hai sự kiện là các tham số cho phép tôi xác định xem fling có đáng chú ý không).

    public class SelectFilterActivity extends Activity implements
        View.OnClickListener, OnTouchListener { ...
  • Nếu tôi thực hiện một tùy chỉnh View, như thế GestureImageViewsẽ kéo dài, ImageViewtôi không biết làm thế nào để biết hoạt động flingđã xảy ra từ chế độ xem. Trong mọi trường hợp, tôi đã thử cách này và các phương thức không được gọi khi tôi chạm vào màn hình.

Tôi thực sự chỉ cần một ví dụ cụ thể về việc này trên các khung nhìn. Những gì, khi nào và làm thế nào tôi nên đính kèm này listener? Tôi cần phải có khả năng phát hiện các nhấp chuột duy nhất.

// 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;
        }
    }
});

Có thể đặt chế độ xem trong suốt phía trên màn hình của tôi để chụp flings không?

Nếu tôi chọn không cho các inflatechế độ xem hình ảnh con của tôi từ XML, tôi có thể chuyển GestureDetectortham số dưới dạng tham số cho lớp con mới ImageViewmà tôi tạo không?

Đây là hoạt động rất đơn giản mà tôi đang cố gắng để flingphát hiện hoạt động cho: ChọnFilterActivity (Chuyển thể từ photostream) .

Tôi đã xem xét các nguồn này:

Không có gì đã làm việc cho tôi cho đến nay và tôi đã hy vọng cho một số gợi ý.


Làm thế nào để giải quyết vấn đề này? Vui lòng trả lời stackoverflow.com/questions/60464912/ từ
Bishwash

Câu trả lời:


818

Cảm ơn Code Shogun , người mà tôi đã thích nghi với hoàn cảnh của mình.

Hãy để hoạt động của bạn thực hiện OnClickListenernhư bình thường:

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;
    }
  }
}

Đính kèm người nghe cử chỉ của bạn với tất cả các chế độ xem bạn thêm vào bố cục chính;

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

Xem trong sự sợ hãi khi các phương thức bị ghi đè của bạn bị tấn công, cả onClick(View v)hoạt động và onFlingngười nghe cử chỉ.

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

Bài nhảy 'fling' là tùy chọn nhưng được khuyến khích.


109
Cảm ơn bạn cho mã này! Nó rất hữu ích. Tuy nhiên, tôi đã gặp phải một sự cố rất bực bội trong khi cố gắng làm cho cử chỉ hoạt động. Trong SimpleOnGestureListener, tôi phải ghi đè onDown cho bất kỳ cử chỉ nào của tôi để đăng ký. Nó chỉ có thể trả về true nhưng tôi phải được xác định. Tái bút: Tôi không biết đó là bản sửa đổi api hay phần cứng của mình, nhưng tôi đang sử dụng 1.5 trên HTC Droid Eris.
Cdsboy

Tôi đã thử mã của bạn và không vấn đề gì nếu tôi vuốt hoặc nhấp (bằng chuột, vì tôi làm việc trong trình giả lập), tôi luôn nhận được một Toast mà tôi đã xác định trong phương thức onClick, vì vậy trình giả lập chỉ phát hiện các lần nhấp, không có thao tác vuốt. Tại sao nó như vậy?
lomza

Tôi đã thử mã này và nó không hoạt động. vẫn không thể cuộn được khi tôi áp dụng trình nghe onClick cho một trong các chế độ xem con trong chế độ xem thư viện của tôi
Jonathan

Iomza: bạn đã thử đặt các tuyên bố phá vỡ và bước qua mã của bạn chưa?
IgorGanapolsky

Kudos cho việc sử dụng một lớp bên trong! Cách tiếp cận rất sạch sẽ.
IgorGanapolsky

211

Một trong những câu trả lời ở trên đề cập đến việc xử lý mật độ pixel khác nhau nhưng đề nghị tính toán các tham số vuốt bằng tay. Điều đáng chú ý là bạn thực sự có thể thu được các giá trị hợp lý theo tỷ lệ từ hệ thống bằng cách sử dụng ViewConfigurationlớp:

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)

Tôi nhận thấy rằng việc sử dụng các giá trị này làm cho "cảm giác" của fling trở nên nhất quán hơn giữa ứng dụng và phần còn lại của hệ thống.


11
Tôi sử dụng swipeMinDistance = vc.getScaledPagingTouchSlop()swipeMaxOffPath = vc.getScaledTouchSlop().
Thomas Ahle

8
getScaledTouchSlopcho tôi kết quả bù đắp rất ít, vụng về. Ví dụ: chỉ có 24 pixel trên màn hình cao 540, rất khó để giữ nó trong phạm vi bằng ngón tay. : S
WonderCsabo

148

Tôi làm điều đó một chút khác biệt, và đã viết một lớp máy dò bổ sung thực hiện View.onTouchListener

onCreatechỉ đơn giản là thêm nó vào bố cục thấp nhất như thế này:

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

trong đó id.lowestLayout là id.xxx cho chế độ xem thấp nhất trong phân cấp bố cục và lowLayout được khai báo là RelativeLayout

Và sau đó là lớp phát hiện vuốt hoạt động thực tế:

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;
}

}

Hoạt động thực sự tốt cho tôi!


1
Điều này thực sự giúp tôi áp dụng chức năng cử chỉ dễ dàng hơn nhiều và yêu cầu nối dây "ít" hơn: D Cảm ơn @Thomas
nemeisfixx

5
Điều này trông giống như một lớp tiện ích gọn gàng - nhưng tôi nghĩ rằng bốn phương thức ... vuốt () của bạn nên là các giao diện
Ai đó ở đâu đó vào

2
những lợi nhuận này không nên có (dòng "chúng tôi không tiêu thụ sự kiện"), phải không? Nó vô hiệu hóa tính năng cuộn dọc.
Marek Sebera

5
cụ thể là phương thức onTouch (). đầu tiên, nếu delta X không đủ lớn, nó sẽ trả về mà không kiểm tra delta Y. kết quả là không bao giờ phát hiện các thao tác vuốt trái phải. thứ hai, nó cũng không nên trả về true nếu nó không tìm thấy thao tác vuốt. thứ ba, nó không nên trở lại đúng với hành động xuống. điều này ngăn bất kỳ người nghe nào khác như onClick hoạt động.
Jeffrey Blattman

1
@Piotr không phải là vấn đề miễn là đối tượng giữ tham chiếu có cùng phạm vi với chính hoạt động đó. vấn đề xảy ra khi bạn giữ một tham chiếu đến một hoạt động ở một nơi có phạm vi lớn hơn hoạt động ... chẳng hạn như từ một thành viên tĩnh chẳng hạn.
Jeffrey Blattman

94

Tôi sửa đổi một chút và sửa chữa giải pháp từ Thomas Fankhauser

Toàn bộ hệ thống bao gồm từ hai tệp, 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);

}

Máy dò

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;
    }

}

nó được sử dụng như thế này:

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

Và trong quá trình triển khai, Activitybạn cần triển khai các phương thức từ SwipeInterface và bạn có thể tìm hiểu xem View the Swipe Event được gọi trên đó.

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

Tôi hơi sửa đổi nó một lần nữa, xem v.performClick();, được sử dụng để không tiêu thụ sự kiện cho OnClickListener, nếu được đặt trên cùng một chế độ xem
Marek Sebera

Xin chào, tôi là người mới bắt đầu nên câu hỏi này có thể rất rõ ràng hoặc tầm thường nhưng xin hãy trả lời. Phần mà bạn đã viết, nó được sử dụng như: ActivitySwipeDetector swipe = new ActivitySwipeDetector (this); Tuyên bố này sẽ là một phần của MainActivity, đúng không? Sau đó, "cái này" sẽ là một hoạt động của MainActivity. Trong khi đó, hàm tạo lấy một thể hiện của SwipeInterface. Xin vui lòng giúp tôi ra khỏi đây. Cảm ơn rất nhiều.
Sô cô la

@Chocolava tạo câu hỏi mới, bình luận không phải là nơi tốt để hỏi như thế này.
Marek Sebera

@MarekSebera cái này không hoạt động với ScrollView & ListView? Làm thế nào để xử lý chúng?
Đức Trần

@silentbang một lần nữa, đây không phải là nơi để đặt câu hỏi như vậy. vui lòng tạo chủ đề câu hỏi mới.
Marek Sebera

65

Mã phát hiện cử chỉ vuốt ở trên là rất hữu ích! Tuy nhiên, bạn có thể muốn làm cho mật độ giải pháp này không rõ ràng bằng cách sử dụng các giá trị tương đối sau (REL_SWIPE)thay vì các giá trị tuyệt đối(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);

8
+1 để đưa cái này lên. Lưu ý rằng D Mật độMetrics.d mật độDpi đã được giới thiệu trong API 4. Để tương thích ngược với API 1, thay vào đó, hãy sử dụng D Mật độMetrics.d mật độ. Điều này sau đó thay đổi phép tính thành SWIPE_MIN_DISTANCE * dm.d mật độ.
Thane Anthem

Bạn lấy số 160.0f ở đâu?
IgorGanapolsky

developer.android.com/guide/practices/sc Greens_support.html pixel độc lập với mật độ (dp) Việc chuyển đổi các đơn vị dp thành pixel màn hình rất đơn giản: px = dp * (dpi / 160)
paiego

Tôi đã tìm kiếm tất cả cho điều này. KHÔNG có ví dụ nào về onFling () trên Internet có điều này, điều này sẽ dẫn đến UX kém. Cảm ơn!
Sandy

160.0f là xuất phát từ 160 DPI, mật độ tiêu chuẩn dựa trên DP (pixel độc lập với mật độ pixel). chung tĩnh tĩnh DENSITY_MEDIUM Đã thêm vào API cấp 4 DPI lượng tử hóa tiêu chuẩn cho màn hình mật độ trung bình. Giá trị không đổi: 160 (0x000000a0)
paiego

35

Phiên bản giải pháp của tôi được đề xuất bởi Thomas FankhauserMarek Sebera (không xử lý các thao tác vuốt dọc):

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;
    }

}

bất cứ ai có thể xin vui lòng cho tôi biết làm thế nào để gọi lớp. ActivitySwipeDetector swipe = new ActivitySwipeDetector (cái này); rõ ràng là đưa ra lỗi, vì không có nhà xây dựng như vậy. Tôi có nên cho ActivitySwipeDetector swipe = new ActivitySwipeDetector (this, null);
abdfahim

@AbdullahFahim ActivitySwipeDetector (cái này, YourActivity.this);
Anton Kashpor

25

Câu hỏi này khá cũ và vào tháng 7 năm 2011 Google đã phát hành Gói tương thích, phiên bản 3) bao gồm các phiên bản ViewPagerhoạt động với Android 1.6 trở lên. Các GestureListenercâu trả lời được đăng cho câu hỏi này không tạo cảm giác rất thanh lịch trên Android. Nếu bạn đang tìm mã được sử dụng để chuyển đổi giữa các ảnh trong Thư viện Android hoặc chuyển đổi chế độ xem trong ứng dụng Play Market mới thì chắc chắn đó làViewPager .

Dưới đây là một số liên kết để biết thêm:


Một vấn đề với ViewPager là bạn không kiểm soát các tham số khoảng cách và vận tốc cho cử chỉ bay.
almalkawi

ViewPager không được sử dụng trong thư viện.
Anthony

18

Có một giao diện tích hợp mà bạn có thể sử dụng trực tiếp cho tất cả các cử chỉ:
Dưới đây là lời giải thích cho người dùng ở mức cơ bản: nhập mô tả hình ảnh ở đây Có 2 cách nhập cẩn thận khi chọn cả hai đều khác nhau. nhập mô tả hình ảnh ở đây nhập mô tả hình ảnh ở đây


1
Và các bước tiếp theo là gì? Làm thế nào để đặt người nghe đó đến một chế độ xem cụ thể? Và nếu quan điểm này là một phần của một mảnh?
Stan

16

Có một số đề xuất trên web (và trang này) để sử dụng ViewConfiguration. getScaledTouchSlop () để có giá trị tỷ lệ thiết bị cho SWIPE_MIN_DISTANCE.

getScaledTouchSlop()được dành cho khoảng cách "ngưỡng cuộn ", không phải vuốt. Khoảng cách ngưỡng cuộn phải nhỏ hơn khoảng cách ngưỡng "xoay giữa trang". Ví dụ: chức năng này trả về 12 pixel trên Samsung GS2 của tôi và các ví dụ được trích dẫn trong trang này là khoảng 100 pixel.

Với API cấp 8 (Android 2.2, Froyo), bạn đã có getScaledPagingTouchSlop(), dự định vuốt trang. Trên thiết bị của tôi, nó trả về 24 (pixel). Vì vậy, nếu bạn ở Cấp API <8, tôi nghĩ "2 * getScaledTouchSlop()" phải là ngưỡng vuốt "chuẩn". Nhưng những người dùng ứng dụng của tôi với màn hình nhỏ nói với tôi rằng nó quá ít ... Như trên ứng dụng của tôi, bạn có thể cuộn theo chiều dọc và thay đổi trang theo chiều ngang. Với giá trị đề xuất, đôi khi họ thay đổi trang thay vì cuộn.


13

Cũng như một sự tăng cường nhỏ.

Lý do chính cho khối thử / bắt là e1 có thể là null cho chuyển động ban đầu. ngoài việc thử / bắt, bao gồm kiểm tra null và trả về. tương tự như sau

if (e1 == null || e2 == null) return false;
try {
...
} catch (Exception e) {}
return false;

12

Có rất nhiều thông tin tuyệt vời ở đây. Thật không may, rất nhiều mã xử lý fling này nằm rải rác trên các trang web khác nhau trong các trạng thái hoàn thành khác nhau, mặc dù người ta sẽ nghĩ rằng điều này là cần thiết cho nhiều ứng dụng.

Tôi đã dành thời gian để tạo ra một trình nghe fling để xác minh rằng các điều kiện thích hợp được đáp ứng. Tôi đã thêm một trình nghe fling trang để thêm nhiều kiểm tra hơn để đảm bảo rằng các flings đáp ứng ngưỡng cho các lần lật trang. Cả hai trình nghe này cho phép bạn dễ dàng hạn chế các cú ném vào trục ngang hoặc dọc. Bạn có thể thấy nó được sử dụng như thế nào trong chế độ xem cho hình ảnh trượt . Tôi xác nhận rằng những người ở đây đã thực hiện hầu hết các nghiên cứu --- Tôi vừa mới đưa nó vào một thư viện có thể sử dụng được.

Vài ngày qua đại diện cho cú đâm đầu tiên của tôi vào việc mã hóa trên Android; mong đợi nhiều hơn nữa sẽ đến


Tôi muốn thực hiện cử chỉ vuốt qua 2 ngón tay. Hãy giúp tôi ra!
Gaurav Arora

12

Đây là một câu trả lời kết hợp của hai câu trả lời ở trên, nếu bất cứ ai muốn thực hiện làm việc.

package com.yourapplication;

import android.content.Context;
import android.view.GestureDetector;
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewConfiguration;

public abstract class OnSwipeListener implements View.OnTouchListener {

    private final GestureDetector gestureDetector;

    public OnSwipeListener(Context context){
        gestureDetector = new GestureDetector(context, new OnSwipeGestureListener(context));
        gestureDetector.setIsLongpressEnabled(false);
    }

    @Override
    public boolean onTouch(View view, MotionEvent event) {
        return gestureDetector.onTouchEvent(event);
    }

    private final class OnSwipeGestureListener extends GestureDetector.SimpleOnGestureListener {

        private final int minSwipeDelta;
        private final int minSwipeVelocity;
        private final int maxSwipeVelocity;

        private OnSwipeGestureListener(Context context) {
            ViewConfiguration configuration = ViewConfiguration.get(context);
            // We think a swipe scrolls a full page.
            //minSwipeDelta = configuration.getScaledTouchSlop();
            minSwipeDelta = configuration.getScaledPagingTouchSlop();
            minSwipeVelocity = configuration.getScaledMinimumFlingVelocity();
            maxSwipeVelocity = configuration.getScaledMaximumFlingVelocity();
        }

        @Override
        public boolean onDown(MotionEvent event) {
            // Return true because we want system to report subsequent events to us.
            return true;
        }

        // NOTE: see http://stackoverflow.com/questions/937313/android-basic-gesture-detection
        @Override
        public boolean onFling(MotionEvent event1, MotionEvent event2, float velocityX,
                               float velocityY) {

            boolean result = false;
            try {
                float deltaX = event2.getX() - event1.getX();
                float deltaY = event2.getY() - event1.getY();
                float absVelocityX = Math.abs(velocityX);
                float absVelocityY = Math.abs(velocityY);
                float absDeltaX = Math.abs(deltaX);
                float absDeltaY = Math.abs(deltaY);
                if (absDeltaX > absDeltaY) {
                    if (absDeltaX > minSwipeDelta && absVelocityX > minSwipeVelocity
                            && absVelocityX < maxSwipeVelocity) {
                        if (deltaX < 0) {
                            onSwipeLeft();
                        } else {
                            onSwipeRight();
                        }
                    }
                    result = true;
                } else if (absDeltaY > minSwipeDelta && absVelocityY > minSwipeVelocity
                        && absVelocityY < maxSwipeVelocity) {
                    if (deltaY < 0) {
                        onSwipeTop();
                    } else {
                        onSwipeBottom();
                    }
                }
                result = true;
            } catch (Exception e) {
                e.printStackTrace();
            }
            return result;
        }
    }

    public void onSwipeLeft() {}

    public void onSwipeRight() {}

    public void onSwipeTop() {}

    public void onSwipeBottom() {}
}

Cảm ơn bạn đã thực hiện tốt. Ngoài ra tôi sẽ đề nghị kiểm tra absDeltaY > minSwipeDelta, absVelocityY > minSwipeVelocity, absVelocityY < maxSwipeVelocitychỉ trong trường hợp nếu minSwipeDelta ! = getScaledTouchSlop , minSwipeVelocity ! = getScaledMinimumFlingVelocity , maxSwipeVelocity ! = getScaledMaximumFlingVelocity , Tức là để kiểm tra chỉ khi những cái gọi là “mặc định” (Tôi có nghĩa getScaledTouchSlop, getScaledMinimumFlingVelocity, getScaledMaximumFlingVelocity) giá trị được thu nhỏ lại hoặc thay đổi theo của bạn mong muốn riêng.
Elia12345

Vấn đề là theo mã nguồn , các giá trị "mặc định" được đề cập đã được kiểm tra bởi GestureDetector và OnFling chỉ được kích hoạt nếu chúng được xác nhận (bằng cách kích hoạt chỉ diễn ra trong trường hợp ACTION_UP, không ACTION_MOVEhoặc ACTION_POINTER_UP, tức là chỉ một kết quả của cử chỉ nhận thức đầy đủ). (Tôi chưa kiểm tra các phiên bản API khác, vì vậy các bình luận được đánh giá cao).
Elia12345

11

Bạn có thể sử dụng thư viện droidQuery để xử lý các cú ném, nhấp chuột, nhấp chuột dài và các sự kiện tùy chỉnh. Việc triển khai được xây dựng dựa trên câu trả lời trước của tôi bên dưới, nhưng droidQuery cung cấp một cú pháp đơn giản, khéo léo:

//global variables    private boolean isSwiping = false;
private SwipeDetector.Direction swipeDirection = null;
private View v;//must be instantiated before next call.

//swipe-handling code
$.with(v).swipe(new Function() {
    @Override
    public void invoke($ droidQuery, Object... params) {
        if (params[0] == SwipeDetector.Direction.START)
            isSwiping = true;
        else if (params[0] == SwipeDetector.Direction.STOP) {
            if (isSwiping) {                    isSwiping = false;
                if (swipeDirection != null) {
                    switch(swipeDirection) {
                        case DOWN :                                //TODO: Down swipe complete, so do something
                            break;
                        case UP :
                            //TODO: Up swipe complete, so do something
                            break;
                        case LEFT :
                            //TODO: Left swipe complete, so do something
                            break;
                        case RIGHT :
                            //TODO: Right swipe complete, so do something
                            break;
                        default :                                break;
                    }
                }                }
        }
        else {
            swipeDirection = (SwipeDetector.Direction) params[0];
        }
    }
});

Câu trả lời gốc

Câu trả lời này sử dụng kết hợp các thành phần từ các câu trả lời khác ở đây. Nó bao gồm các SwipeDetectorlớp, có một giao diện bên trong để lắng nghe các sự kiện. Tôi cũng cung cấp một cách RelativeLayoutđể hiển thị cách ghi đè phương thức Viewcủa một onTouchphương thức để cho phép cả các sự kiện vuốt và các sự kiện được phát hiện khác (chẳng hạn như nhấp chuột hoặc nhấp chuột dài).

SwipeDetector

package self.philbrown;

import android.view.MotionEvent;
import android.view.View;
import android.view.ViewConfiguration;

/**
 * Detect Swipes on a per-view basis. Based on original code by Thomas Fankhauser on StackOverflow.com,
 * with adaptations by other authors (see link).
 * @author Phil Brown
 * @see <a href="http://stackoverflow.com/questions/937313/android-basic-gesture-detection">android-basic-gesture-detection</a>
 */
public class SwipeDetector implements View.OnTouchListener
{
    /**
     * The minimum distance a finger must travel in order to register a swipe event.
     */
    private int minSwipeDistance;

    /** Maintains a reference to the first detected down touch event. */
    private float downX, downY;

    /** Maintains a reference to the first detected up touch event. */
    private float upX, upY;

    /** provides access to size and dimension contants */
    private ViewConfiguration config;

    /**
     * provides callbacks to a listener class for various swipe gestures.
     */
    private SwipeListener listener;

    public SwipeDetector(SwipeListener listener)
    {
        this.listener = listener;
    }


    /**
     * {@inheritDoc}
     */
    public boolean onTouch(View v, MotionEvent event)
    {
        if (config == null)
        {
                config = ViewConfiguration.get(v.getContext());
                minSwipeDistance = config.getScaledTouchSlop();
        }

        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) > minSwipeDistance)
            {
                // left or right
                if (deltaX < 0)
                {
                        if (listener != null)
                        {
                                listener.onRightSwipe(v);
                                return true;
                        }
                }
                if (deltaX > 0)
                {
                        if (listener != null)
                        {
                                listener.onLeftSwipe(v);
                                return true;
                        }
                }
            }

            // swipe vertical?
            if(Math.abs(deltaY) > minSwipeDistance)
            {
                // top or down
                if (deltaY < 0)
                {
                        if (listener != null)
                        {
                                listener.onDownSwipe(v);
                                return true;
                        }
                }
                if (deltaY > 0)
                {
                        if (listener != null)
                        {
                                listener.onUpSwipe(v);
                                return true;
                        }
                }
            }
        }
        return false;
    }

    /**
     * Provides callbacks to a registered listener for swipe events in {@link SwipeDetector}
     * @author Phil Brown
     */
    public interface SwipeListener
    {
        /** Callback for registering a new swipe motion from the bottom of the view toward its top. */
        public void onUpSwipe(View v);
        /** Callback for registering a new swipe motion from the left of the view toward its right. */
        public void onRightSwipe(View v);
        /** Callback for registering a new swipe motion from the right of the view toward its left. */
        public void onLeftSwipe(View v);
        /** Callback for registering a new swipe motion from the top of the view toward its bottom. */
        public void onDownSwipe(View v);
    }
}

Chế độ đánh chặn vuốt

package self.philbrown;

import android.content.Context;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.widget.RelativeLayout;

import com.npeinc.module_NPECore.model.SwipeDetector;
import com.npeinc.module_NPECore.model.SwipeDetector.SwipeListener;

/**
 * View subclass used for handling all touches (swipes and others)
 * @author Phil Brown
 */
public class SwipeInterceptorView extends RelativeLayout
{
    private SwipeDetector swiper = null;

    public void setSwipeListener(SwipeListener listener)
    {
        if (swiper == null)
            swiper = new SwipeDetector(listener);
    }

    public SwipeInterceptorView(Context context) {
        super(context);
    }

    public SwipeInterceptorView(Context context, AttributeSet attrs) {
        super(context, attrs);
    }

    public SwipeInterceptorView(Context context, AttributeSet attrs, int defStyle) {
        super(context, attrs, defStyle);
    }

    @Override
    public boolean onTouchEvent(MotionEvent e)
    {
        boolean swipe = false, touch = false;
        if (swiper != null)
            swipe = swiper.onTouch(this, e);
        touch = super.onTouchEvent(e);
        return swipe || touch;
    }
}

1
Tôi đã thử thực hiện điều này trên một khung nhìn có chứa các yếu tố có thể nhấp. Khi thao tác vuốt bắt đầu qua phần tử có thể nhấp (ví dụ: chế độ xem danh sách đã được đăng ký trình nghe onItemClick), thì onTouchEvent không bao giờ được gọi. Do đó, người dùng không thể bắt đầu vuốt qua phần tử có thể nhấp, điều này không may cho tôi và tôi vẫn đang cố gắng tìm ra cách khắc phục điều này, vì các phần tử có thể nhấp của chúng tôi chiếm khá nhiều không gian xem và chúng tôi vẫn muốn hỗ trợ vuốt cho toàn bộ quan điểm. Nếu một lần vuốt không bắt đầu qua một yếu tố có thể nhấp, thì nó hoạt động hoàn hảo.
Lo-Tan

@ Lo-Tân, điều này xảy ra vì mục có thể click của bạn là một cái nhìn đứa trẻ, và vì thế trên đầu trang của SwipeInterceptorView, vì vậy nhấp chuột của nó được xử lý đầu tiên. Bạn có thể khắc phục điều này bằng cách thực hiện cơ chế nhấp chuột của riêng mình bằng cách triển khai onTouchListenerhoặc như một công việc xung quanh bạn có thể lắng nghe các nhấp chuột dài thay vì nhấp chuột (xem View.setOnLongClickListener).
Phil

Tôi thực sự đang cố gắng điều đó vào lúc này. Hoặc có thể hủy sự kiện nhấp nếu họ bắt đầu kéo :) Cảm ơn nhiều.
Lo-Tan

Một giải pháp là gắn trình phát hiện vuốt vào mọi chế độ xem trong ứng dụng của bạn. Một cách khác là triển khai onInterceptTouchEvent trong SwipeInterceptorView của bạn.
Edward Falk

7

Tôi biết quá muộn để trả lời nhưng tôi vẫn đang đăng Phát hiện vuốt cho ListView rằng Cách sử dụng Trình nghe cảm ứng vuốt trong Mục ListView .

Chuyển hướng: Exterminator13 (một trong những câu trả lời trong trang này)

Tạo một ActivitySwipeDetector. Class

package com.example.wocketapp;

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 = "SwipeDetector";
    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();
                v.getParent().requestDisallowInterceptTouchEvent(false);
                return true;
            }

        case MotionEvent.ACTION_MOVE:
            {
                float y_up = event.getY();
                float deltaY = y_up - downY;
                float absDeltaYMove = Math.abs(deltaY);

                if (absDeltaYMove > 60) 
                {
                    v.getParent().requestDisallowInterceptTouchEvent(false);
                } 
                else
                {
                    v.getParent().requestDisallowInterceptTouchEvent(true);
                }
            }

            break;

            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.e(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) 
                {
                     v.getParent().requestDisallowInterceptTouchEvent(true);
                    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)));
                }

                 v.getParent().requestDisallowInterceptTouchEvent(false);

            }
        }
        return false;
    }
    public interface SwipeInterface 
    {

        public void onLeftToRight(View v);

        public void onRightToLeft(View v);
    }

}

Gọi nó từ lớp hoạt động của bạn như thế này:

yourLayout.setOnTouchListener(new ActivitySwipeDetector(this, your_activity.this));

Và đừng quên triển khai SwipeInterface sẽ cung cấp cho bạn hai phương thức @override:

    @Override
    public void onLeftToRight(View v) 
    {
        Log.e("TAG", "L to R");
    }

    @Override
    public void onRightToLeft(View v) 
    {
        Log.e("TAG", "R to L");
    }

Tôi thấy rằng một MAX_OFF_PATH = 5 * vc.getScaledPagingTouchSlop()thoải mái hơn cho một ngón tay cái vuốt tự nhiên đi trong một vòng cung nhẹ.
qix

4

Cử chỉ là những chuyển động tinh tế để kích hoạt sự tương tác giữa màn hình cảm ứng và người dùng. Nó kéo dài trong khoảng thời gian từ lần chạm đầu tiên trên màn hình đến điểm khi ngón tay cuối cùng rời khỏi bề mặt.

Android cung cấp cho chúng ta một lớp có tên là GestureDetector bằng cách sử dụng chúng ta có thể phát hiện các cử chỉ phổ biến như chạm xuống và vuốt lên, vuốt dọc và ngang (fling), nhấn dài và ngắn, chạm hai lần, v.v. . và gắn người nghe với họ.

Làm cho lớp Activity của chúng ta triển khai GestureDetector.OnDoubleTapListener (để phát hiện cử chỉ chạm hai lần) và giao diện GestureDetector.OnGestureListener và thực hiện tất cả các phương thức trừu tượng. Để biết thêm thông tin. bạn có thể truy cập https://developer.android.com/training/gestures/detector.html . Phép lịch sự

Đối với thử nghiệm Demo. GestureDetectorDemo


4

Nếu bạn không muốn tạo một lớp riêng biệt hoặc làm cho mã phức tạp,
bạn chỉ cần tạo một biến GestureDetector bên trong OnTouchListener và làm cho mã của bạn dễ dàng hơn

namVyuVar có thể là bất kỳ tên nào của Chế độ xem mà bạn cần đặt người nghe

namVyuVar.setOnTouchListener(new View.OnTouchListener()
{
    @Override
    public boolean onTouch(View view, MotionEvent MsnEvtPsgVal)
    {
        flingActionVar.onTouchEvent(MsnEvtPsgVal);
        return true;
    }

    GestureDetector flingActionVar = new GestureDetector(getApplicationContext(), new GestureDetector.SimpleOnGestureListener()
    {
        private static final int flingActionMinDstVac = 120;
        private static final int flingActionMinSpdVac = 200;

        @Override
        public boolean onFling(MotionEvent fstMsnEvtPsgVal, MotionEvent lstMsnEvtPsgVal, float flingActionXcoSpdPsgVal, float flingActionYcoSpdPsgVal)
        {
            if(fstMsnEvtPsgVal.getX() - lstMsnEvtPsgVal.getX() > flingActionMinDstVac && Math.abs(flingActionXcoSpdPsgVal) > flingActionMinSpdVac)
            {
                // TskTdo :=> On Right to Left fling

                return false;
            }
            else if (lstMsnEvtPsgVal.getX() - fstMsnEvtPsgVal.getX() > flingActionMinDstVac && Math.abs(flingActionXcoSpdPsgVal) > flingActionMinSpdVac)
            {
                // TskTdo :=> On Left to Right fling

                return false;
            }

            if(fstMsnEvtPsgVal.getY() - lstMsnEvtPsgVal.getY() > flingActionMinDstVac && Math.abs(flingActionYcoSpdPsgVal) > flingActionMinSpdVac)
            {
                // TskTdo :=> On Bottom to Top fling

                return false;
            }
            else if (lstMsnEvtPsgVal.getY() - fstMsnEvtPsgVal.getY() > flingActionMinDstVac && Math.abs(flingActionYcoSpdPsgVal) > flingActionMinSpdVac)
            {
                // TskTdo :=> On Top to Bottom fling

                return false;
            }
            return false;
        }
    });
});

3

Đối với tất cả: đừng quên trường hợp MotionEvent.ACTION_CANCEL:

nó gọi trong 30% số lần vuốt mà không có ACTION_UP

và bằng với ACTION_UP trong trường hợp này


2

Tôi đã chọn một Lớp chung chung hơn, tôi lấy lớp của Tomas và thêm Giao diện gửi các sự kiện đến Hoạt động hoặc Đoạn của bạn. nó sẽ đăng ký trình nghe trên hàm tạo, vì vậy hãy chắc chắn rằng bạn triển khai giao diện hoặc ClassCastException sẽ là thorwn. giao diện trả về một trong bốn int cuối cùng được xác định trong lớp và sẽ trả về khung nhìn mà nó được kích hoạt.

import android.app.Activity;
import android.support.v4.app.Fragment;
import android.util.Log;
import android.view.MotionEvent;
import android.view.View;

public class SwipeDetector implements View.OnTouchListener{

    static final int MIN_DISTANCE = 100;
    private float downX, downY, upX, upY;
    public final static int RIGHT_TO_LEFT=1;
    public final static int LEFT_TO_RIGHT=2;
    public final static int TOP_TO_BOTTOM=3;
    public final static int BOTTOM_TO_TOP=4;
    private View v;

    private onSwipeEvent swipeEventListener;


    public SwipeDetector(Activity activity,View v){
        try{
            swipeEventListener=(onSwipeEvent)activity;
        }
        catch(ClassCastException e)
        {
            Log.e("ClassCastException",activity.toString()+" must implement SwipeDetector.onSwipeEvent");
        } 
        this.v=v;
    }
    public SwipeDetector(Fragment fragment,View v){
        try{
            swipeEventListener=(onSwipeEvent)fragment;
        }
        catch(ClassCastException e)
        {
            Log.e("ClassCastException",fragment.toString()+" must implement SwipeDetector.onSwipeEvent");
        } 
        this.v=v;
    }


    public void onRightToLeftSwipe(){   
        swipeEventListener.SwipeEventDetected(v,RIGHT_TO_LEFT);
    }

    public void onLeftToRightSwipe(){   
        swipeEventListener.SwipeEventDetected(v,LEFT_TO_RIGHT);
    }

    public void onTopToBottomSwipe(){   
        swipeEventListener.SwipeEventDetected(v,TOP_TO_BOTTOM);
    }

    public void onBottomToTopSwipe(){
        swipeEventListener.SwipeEventDetected(v,BOTTOM_TO_TOP);
    }

    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;

            //HORIZONTAL SCROLL
            if(Math.abs(deltaX) > Math.abs(deltaY))
            {
                if(Math.abs(deltaX) > MIN_DISTANCE){
                    // left or right
                    if(deltaX < 0) 
                    {
                        this.onLeftToRightSwipe();
                        return true;
                    }
                    if(deltaX > 0) {
                        this.onRightToLeftSwipe();
                        return true; 
                    }
                }
                else {
                    //not long enough swipe...
                    return false; 
                }
            }
            //VERTICAL SCROLL
            else 
            {
                if(Math.abs(deltaY) > MIN_DISTANCE){
                    // top or down
                    if(deltaY < 0) 
                    { this.onTopToBottomSwipe();
                    return true; 
                    }
                    if(deltaY > 0)
                    { this.onBottomToTopSwipe(); 
                    return true;
                    }
                }
                else {
                    //not long enough swipe...
                    return false;
                }
            }

            return true;
        }
        }
        return false;
    }
    public interface onSwipeEvent
    {
        public void SwipeEventDetected(View v , int SwipeType);
    }

}
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.