Deteksi gerakan isyarat pada tata letak kisi

1106

Saya ingin mendapatkan flingdeteksi gerakan yang berfungsi di aplikasi Android saya.

Yang saya miliki adalah GridLayoutyang berisi 9 ImageViews. Sumbernya dapat ditemukan di sini: Layout Grid Romain Guys .

File yang saya ambil adalah dari aplikasi Photostream Romain Guy dan hanya sedikit diadaptasi.

Untuk situasi klik sederhana, saya hanya perlu mengatur onClickListeneragar setiap yang ImageViewsaya tambahkan menjadi alat utama activityyang diterapkan View.OnClickListener. Tampaknya jauh lebih rumit untuk mengimplementasikan sesuatu yang mengenali a fling. Saya kira ini karena mungkin span views?

  • Jika aktivitas saya menerapkan, OnGestureListenersaya tidak tahu cara mengaturnya sebagai pendengar gerakan untuk Gridatau Imagepandangan yang saya tambahkan.

    public class SelectFilterActivity extends Activity implements
       View.OnClickListener, OnGestureListener { ...
    
  • Jika aktivitas saya diimplementasikan OnTouchListenermaka saya tidak memiliki onFlingmetode untuk override(memiliki dua peristiwa sebagai parameter yang memungkinkan saya untuk menentukan apakah melemparkan itu penting).

    public class SelectFilterActivity extends Activity implements
        View.OnClickListener, OnTouchListener { ...
    
  • Jika saya membuat kebiasaan View, seperti GestureImageViewitu meluas ImageViewsaya tidak tahu bagaimana cara mengetahui aktivitas yang flingtelah terjadi dari tampilan. Bagaimanapun, saya mencoba ini dan metode tidak dipanggil ketika saya menyentuh layar.

Saya benar-benar hanya perlu contoh nyata dari ini bekerja lintas pandangan. Apa, kapan dan bagaimana saya harus melampirkan ini listener? Saya harus dapat mendeteksi satu klik juga.

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

Apakah mungkin untuk meletakkan tampilan transparan di atas layar saya untuk menangkap teman kencan?

Jika saya memilih untuk tidak inflatemelihat gambar anak saya dari XML, bisakah saya meneruskan GestureDetectorsebagai parameter konstruktor ke subkelas baru ImageViewyang saya buat?

Ini adalah aktivitas yang sangat sederhana yang saya coba agar flingpendeteksiannya bekerja: SelectFilterActivity (Diadaptasi dari photostream) .

Saya telah melihat sumber-sumber ini:

Sejauh ini belum ada yang berhasil dan saya berharap ada beberapa petunjuk.

gav
sumber
Bagaimana cara mengatasi masalah ini? Harap jawab stackoverflow.com/questions/60464912/…
Bishwash

Jawaban:

818

Terima kasih kepada Code Shogun , yang kodenya saya sesuaikan dengan situasi saya.

Biarkan aktivitas Anda menerapkan OnClickListenerseperti biasa:

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

Lampirkan pendengar gerakan Anda ke semua tampilan yang Anda tambahkan ke tata letak utama;

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

Saksikan dengan kagum saat metode Anda yang ditimpa dipukul, baik onClick(View v)aktivitas maupun onFlingpendengar gerakan.

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

Tarian 'melemparkan' adalah opsional tetapi dianjurkan.

gav
sumber
109
Terima kasih untuk kode ini! Itu sangat membantu. Namun, saya bertemu dengan satu tangkapan yang sangat frustasi ketika mencoba untuk membuat gerakan bekerja. Di SimpleOnGestureListener saya, saya harus mengesampingkan onDown agar setiap gerakan saya dapat mendaftar. Itu bisa saja mengembalikan true tetapi saya harus didefinisikan. PS: Saya tidak tahu apakah ini api revisi atau perangkat keras saya, tetapi saya menggunakan 1,5 pada HTC Droid Eris.
Cdsboy
Saya mencoba kode Anda dan tidak masalah jika saya menggesek atau mengklik (dengan mouse saya, karena saya bekerja di emulator), saya selalu mendapatkan Toast yang saya definisikan dalam metode onClick, sehingga emulator hanya mendeteksi klik, tanpa gesek. Kenapa gitu?
lomza
Saya mencoba kode ini dan tidak berhasil. masih tidak dapat menggulir sama sekali ketika saya menerapkan pendengar onClick ke salah satu tampilan anak di dalam tampilan galeri saya
Jonathan
Iomza: apakah Anda mencoba meletakkan pernyataan break dan melangkah melalui kode Anda?
IgorGanapolsky
Pujian untuk menggunakan kelas batin! Pendekatan yang sangat bersih.
IgorGanapolsky
211

Salah satu jawaban di atas menyebutkan penanganan kerapatan piksel yang berbeda tetapi menyarankan untuk menghitung parameter gesek dengan tangan. Perlu dicatat bahwa Anda benar-benar dapat memperoleh nilai yang diskalakan dan masuk akal dari sistem menggunakan ViewConfigurationkelas:

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)

Saya perhatikan bahwa menggunakan nilai-nilai ini menyebabkan "rasa" melemparkan lebih konsisten antara aplikasi dan seluruh sistem.

Xion
sumber
11
Saya menggunakan swipeMinDistance = vc.getScaledPagingTouchSlop()dan swipeMaxOffPath = vc.getScaledTouchSlop().
Thomas Ahle
8
getScaledTouchSlopmemberi saya hasil offset yang sangat sedikit, dengan canggung. Misalnya hanya 24 piksel pada layar tinggi 540, itu sangat sulit untuk menjaga jaraknya dengan jari. : S
WonderCsabo
148

Saya melakukannya sedikit berbeda, dan menulis kelas detektor tambahan yang mengimplementasikan View.onTouchListener

onCreatecukup tambahkan ke tata letak terendah seperti ini:

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

di mana id.lowestLayout adalah id.xxx untuk tampilan terendah dalam hierarki tata letak danelendahLayout dinyatakan sebagai RelativeLayout

Dan kemudian ada kelas swipe detector aktivitas yang sebenarnya:

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

}

Bekerja sangat baik untuk saya!

Thomas Fankhauser
sumber
1
Ini sebenarnya membuatnya lebih mudah bagi saya untuk menerapkan fungsi gerakan, dan membutuhkan kabel "kurang": D Terima kasih
@Thomas
5
Ini terlihat seperti kelas utilitas yang rapi - tapi saya pikir Anda empat pada ... swipe () metode harus antarmuka
Seseorang di suatu tempat
2
pengembalian ini tidak seharusnya ada di sana (baris "kami tidak mengkonsumsi acara"), bukan? Ini menonaktifkan fitur gulir vertikal.
Marek Sebera
5
khususnya, metode onTouch (). pertama, jika delta X tidak cukup besar, ia kembali tanpa memeriksa delta Y. hasilnya adalah tidak pernah mendeteksi gesekan kiri-kanan. kedua, itu juga seharusnya tidak mengembalikan true jika tidak menemukan gesekan. ketiga, seharusnya tidak mengembalikan true saat aksi turun. ini mencegah pendengar lain seperti onClick dari bekerja.
Jeffrey Blattman
1
@Piotr itu bukan masalah asalkan objek yang memegang referensi adalah lingkup yang sama dengan aktivitas itu sendiri. masalah terjadi ketika Anda menyimpan referensi ke aktivitas di tempat yang memiliki cakupan lebih besar daripada aktivitas ... seperti dari anggota statis misalnya.
Jeffrey Blattman
94

Saya sedikit memodifikasi dan memperbaiki solusi dari Thomas Fankhauser

Seluruh sistem terdiri dari dua file, SwipeInterface dan ActivitySwipeDetector


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

}

Detektor

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

}

digunakan seperti ini:

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

Dan dalam mengimplementasikan ActivityAnda perlu mengimplementasikan metode dari SwipeInterface , dan Anda bisa mengetahui dari mana View the Swipe Event dipanggil.

@Override
public void left2right(View v) {
    switch(v.getId()){
        case R.id.swipe_layout:
            // do your stuff here
        break;
    }       
}
Marek Sebera
sumber
Saya sedikit memodifikasinya lagi, lihat v.performClick();, yang digunakan untuk tidak mengkonsumsi acara ke OnClickListener, jika disetel pada tampilan yang sama
Marek Sebera
Hai, saya seorang pemula total jadi pertanyaan ini mungkin sangat jelas atau sepele tapi tolong jawab. Bagian di mana Anda telah menulis, digunakan sebagai: ActivitySwipeDetector swipe = new ActivitySwipeDetector (this); Pernyataan ini akan menjadi bagian dari MainActivity, benar? Kemudian, "ini" akan menjadi aktivitas MainActivity. Sedangkan konstruktor mengambil instance dari SwipeInterface. Mohon bantu saya di sini. Terima kasih banyak.
Chocolava
@ Chocolava membuat pertanyaan baru, komentar bukanlah tempat yang baik untuk bertanya seperti ini.
Marek Sebera
@MarekSebera ini tidak berfungsi dengan ScrollView & ListView? bagaimana cara menanganinya?
Duc Tran
@silentbang lagi, ini bukan tempat untuk bertanya. tolong buat utas pertanyaan baru.
Marek Sebera
65

Kode detektor gerakan isyarat di atas sangat berguna! Namun Anda mungkin ingin menjadikan kerapatan solusi ini agnostik dengan menggunakan nilai relatif berikut (REL_SWIPE)daripada nilai absolut(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);
paiego
sumber
8
+1 untuk mengangkat ini. Perhatikan bahwa DensityMetrics.densityDpi diperkenalkan di API 4. Untuk kompatibilitas dengan API 1, gunakan DensityMetrics.density sebagai gantinya. Ini kemudian mengubah perhitungan menjadi SWIPE_MIN_DISTANCE * dm.density.
Thane Anthem
Di mana Anda mendapatkan nomor 160.0f?
IgorGanapolsky
developer.android.com/guide/practices/screens_support.html Pixel-independent pixel (dp) Konversi unit dp ke piksel layar adalah sederhana: px = dp * (dpi / 160)
paiego
Saya mencari semua ini. TIDAK ADA contoh onFling () di Internet yang memiliki ini, yang akan mengarah pada UX yang buruk. Terima kasih!
Sandy
160.0f adalah yang berasal dari 160 DPI yang merupakan kepadatan standar yang menjadi dasar DP (pixel independent pixel). DENSITY_MEDIUM public int static final Ditambahkan dalam API level 4 DPI terkuantisasi standar untuk layar kepadatan menengah. Nilai Konstan: 160 (0x000000a0)
paiego
35

Versi solusi saya diusulkan oleh Thomas Fankhauser dan Marek Sebera (tidak menangani gesekan vertikal):

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

}
Pembasmi13
sumber
Adakah yang bisa tolong beri tahu saya cara memanggil kelas. ActivitySwipeDetector swipe = new ActivitySwipeDetector (this); jelas memberikan kesalahan, karena tidak ada konstruktor seperti itu. Haruskah saya memberikan ActivitySwipeDetector swipe = new ActivitySwipeDetector (this, null);
abdfahim
@AbdullahFahim ActivitySwipeDetector (ini, YourActivity.this);
Anton Kashpor
25

Pertanyaan ini agak lama dan pada Juli 2011 Google merilis Paket Kompatibilitas, revisi 3) yang mencakup ViewPageryang berfungsi dengan Android 1.6 ke atas. The GestureListenerjawaban diposting untuk pertanyaan ini tidak merasa sangat elegan di Android. Jika Anda mencari kode yang digunakan untuk beralih antar foto di Galeri Android atau mengalihkan tampilan di aplikasi Play Market yang baru, maka sudah pasti ViewPager.

Berikut ini beberapa tautan untuk info lebih lanjut:

georgiecasey
sumber
Satu masalah dengan ViewPager adalah Anda tidak memiliki kontrol parameter jarak dan kecepatan untuk gerakan melempar.
almalkawi
ViewPager tidak digunakan di galeri.
Anthony
18

Ada antarmuka bawaan yang dapat Anda gunakan langsung untuk semua gerakan:
Berikut adalah penjelasan untuk pengguna tingkat dasar: masukkan deskripsi gambar di sini Ada 2 impor hati-hati dalam memilih bahwa keduanya berbeda masukkan deskripsi gambar di sini masukkan deskripsi gambar di sini

Viswanath Lekshmanan
sumber
1
Dan apa langkah selanjutnya? Bagaimana cara mengatur pendengar itu ke tampilan tertentu? Dan bagaimana jika pandangan ini adalah bagian dari sebuah fragmen?
Stan
16

Ada beberapa proposisi di web (dan halaman ini) untuk menggunakan ViewConfiguration. getScaledTouchSlop () untuk memiliki nilai skala perangkat untuk SWIPE_MIN_DISTANCE.

getScaledTouchSlop()ditujukan untuk jarak " scrolling threshold", bukan swipe. Jarak ambang pengguliran harus lebih kecil dari jarak ambang "ayunan antara halaman". Misalnya, fungsi ini mengembalikan 12 piksel pada Samsung GS2 saya, dan contoh yang dikutip di halaman ini sekitar 100 piksel.

Dengan API Level 8 (Android 2.2, Froyo), Anda punya getScaledPagingTouchSlop(), dimaksudkan untuk gesekan halaman. Di perangkat saya, ini mengembalikan 24 (piksel). Jadi jika Anda menggunakan API Level <8, saya pikir "2 * getScaledTouchSlop()" harus menjadi ambang geser "standar". Tetapi pengguna aplikasi saya dengan layar kecil mengatakan kepada saya bahwa itu terlalu sedikit ... Seperti pada aplikasi saya, Anda dapat menggulir secara vertikal, dan mengubah halaman secara horizontal. Dengan nilai yang diusulkan, mereka terkadang mengubah halaman alih-alih menggulir.

Pemetaan
sumber
13

Juga sebagai peningkatan kecil.

Alasan utama untuk blok coba / tangkap adalah bahwa e1 bisa menjadi nol untuk gerakan awal. selain mencoba / menangkap, sertakan tes untuk null dan kembali. mirip dengan yang berikut ini

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

Ada banyak informasi bagus di sini. Sayangnya banyak dari kode pemrosesan ini tersebar di berbagai situs di berbagai negara bagian penyelesaian, meskipun orang akan berpikir ini penting untuk banyak aplikasi.

Saya telah meluangkan waktu untuk membuat pendengar main yang memverifikasi bahwa kondisi yang sesuai terpenuhi. Saya telah menambahkan pendengar halaman penghubung yang menambahkan lebih banyak pemeriksaan untuk memastikan bahwa teman kencan memenuhi ambang batas untuk teman halaman. Kedua pendengar ini memungkinkan Anda untuk membatasi teman kencan dengan sumbu horizontal atau vertikal. Anda dapat melihat bagaimana ini digunakan dalam tampilan untuk menggeser gambar . Saya mengakui bahwa orang-orang di sini telah melakukan sebagian besar penelitian --- Saya baru saja mengumpulkannya di perpustakaan yang dapat digunakan.

Beberapa hari terakhir ini merupakan penusukan pertama saya pada pengkodean di Android; berharap lebih banyak yang akan datang.

Garret Wilson
sumber
Saya ingin menerapkan gerakan menggesek melalui 2 jari. Tolong bantu saya!
Gaurav Arora
12

Ini adalah jawaban gabungan dari dua jawaban di atas, jika ada yang menginginkan implementasi yang berjalan.

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() {}
}
Hai Zhang
sumber
Terima kasih atas implementasi yang sangat baik. Selain itu saya akan menyarankan untuk memeriksa absDeltaY > minSwipeDelta, absVelocityY > minSwipeVelocity, absVelocityY < maxSwipeVelocityhanya dalam kasus jika minSwipeDelta ! = getScaledTouchSlop , minSwipeVelocity ! = getScaledMinimumFlingVelocity , maxSwipeVelocity ! = getScaledMaximumFlingVelocity , Yaitu untuk memeriksa hanya jika ini disebut “default” (Maksudku getScaledTouchSlop, getScaledMinimumFlingVelocity, getScaledMaximumFlingVelocity) nilai-nilai yang ditingkatkan atau diubah sesuai dengan Anda keinginan sendiri.
Elia12345
Intinya adalah bahwa menurut kode sumber , nilai "default" yang disebutkan sudah diperiksa oleh GestureDetector, dan OnFling dipicu hanya jika mereka dikonfirmasi (dengan cara pemicunya hanya terjadi jika ACTION_UP, tidak ACTION_MOVEatau ACTION_POINTER_UP, yaitu hanya sebagai hasil dari gerakan yang terwujud sepenuhnya). (Saya belum memeriksa versi API lainnya, jadi komentar sangat dihargai).
Elia12345
11

Anda dapat menggunakan perpustakaan droidQuery untuk menangani teman kencan, klik, klik panjang, dan acara khusus. Implementasinya dibangun berdasarkan jawaban saya sebelumnya di bawah ini, tetapi droidQuery memberikan sintaks yang sederhana dan apik:

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

Jawaban Asli

Jawaban ini menggunakan kombinasi komponen dari jawaban lain di sini. Ini terdiri dari SwipeDetectorkelas, yang memiliki antarmuka batin untuk mendengarkan acara. Saya juga menyediakan RelativeLayoutuntuk menunjukkan bagaimana untuk menimpa View's onTouchmetode untuk memungkinkan kedua peristiwa menggesek dan acara terdeteksi lainnya (seperti klik atau klik panjang).

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

Gesek Tampilan Pencegat

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;
    }
}
Phil
sumber
1
Saya mencoba menerapkan ini pada tampilan yang mengandung elemen yang dapat diklik. Ketika usapan dimulai dari elemen yang dapat diklik (mis. Tampilan daftar yang memiliki pendengar onItemClick terdaftar), maka onTouchEvent tidak pernah dipanggil. Dengan demikian, pengguna tidak dapat memulai menggesek elemen yang dapat diklik, yang sangat disayangkan bagi saya dan saya masih mencoba mencari cara untuk mengatasinya, karena elemen yang dapat diklik mengambil sedikit ruang tampilan dan kami masih menginginkan dukungan gesek untuk seluruh tampilan. Jika gesek tidak memulai elemen yang dapat diklik, maka itu berfungsi dengan baik.
Lo-Tan
@ Lo-Tan, ini terjadi karena item yang dapat diklik adalah pandangan anak, dan dengan demikian di atas dari SwipeInterceptorView, sehingga klik yang ditangani pertama. Anda dapat memperbaikinya dengan menerapkan mekanisme mengklik Anda sendiri dengan menerapkan onTouchListener, atau sebagai solusi, Anda dapat mendengarkan klik panjang alih-alih klik (lihat View.setOnLongClickListener).
Phil
Saya sebenarnya sedang mencobanya saat itu juga. Atau mungkin membatalkan acara klik jika mereka memulai hambatan :) Terima kasih banyak.
Lo-Tan
Salah satu solusinya adalah melampirkan detektor gesek ke setiap tampilan di aplikasi Anda. Cara lain adalah dengan mengimplementasikan onInterceptTouchEvent di SwipeInterceptorView Anda.
Edward Falk
7

Saya tahu sudah terlambat untuk menjawab, tetapi saya masih memposting Deteksi Gesek untuk ListView bahwa Cara menggunakan Swipe Touch Listener di Item ListView .

Refrence: Pembasmi13 (salah satu jawaban di halaman ini)

Buat satu 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);
    }

}

Sebut saja dari kelas aktivitas Anda seperti ini:

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

Dan jangan lupa untuk mengimplementasikan SwipeInterface yang akan memberi Anda dua metode @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");
    }
Sagar Shah
sumber
Saya menemukan bahwa a MAX_OFF_PATH = 5 * vc.getScaledPagingTouchSlop()lebih nyaman untuk sapuan jempol secara alami bepergian dalam sedikit lengkungan.
qix
4

Gerakan adalah gerakan halus untuk memicu interaksi antara layar sentuh dan pengguna. Ini berlangsung untuk waktu antara sentuhan pertama di layar ke titik ketika jari terakhir meninggalkan permukaan.

Android memberi kita kelas yang disebut GestureDetector yang dapat digunakan untuk mendeteksi gerakan umum seperti mengetuk ke bawah dan ke atas, menggesek secara vertikal dan horizontal (fling), tekan lama dan pendek, ketukan ganda, dll . dan lampirkan pendengar pada mereka.

Buat kelas Aktivitas kami mengimplementasikan GestureDetector.OnDoubleTapListener (untuk deteksi gerakan ketuk ganda) dan antarmuka GestureDetector.OnGestureListener dan menerapkan semua metode abstrak. Untuk info lebih lanjut. Anda dapat mengunjungi https://developer.android.com/training/gestures/detector.html . Kesopanan

Untuk Tes Demo. GestureDetectorDemo

IntelliJ Amiya
sumber
4

Jika Anda tidak ingin membuat kelas terpisah atau membuat kode kompleks,
Anda bisa membuat variabel GestureDetector di dalam OnTouchListener dan membuat kode Anda lebih mudah

namVyuVar dapat berupa nama apa pun dari View yang Anda perlukan untuk mengatur listner

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;
        }
    });
});
Sujay UN
sumber
3

Untuk semua: jangan lupa tentang case MotionEvent.ACTION_CANCEL:

panggilan dalam gesekan 30% tanpa ACTION_UP

dan sama dengan ACTION_UP dalam kasus ini

djdance
sumber
2

Saya menambahkan Kelas yang lebih umum, saya mengambil kelas Tomas dan menambahkan Antarmuka yang mengirim acara ke Aktivitas atau Fragmen Anda. itu akan mendaftarkan pendengar pada konstruktor jadi pastikan Anda mengimplementasikan antarmuka atau ClassCastException akan menjadi milik mereka. antarmuka mengembalikan salah satu dari empat int final yang didefinisikan di kelas dan akan mengembalikan tampilan yang diaktifkan.

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

}
Gal Rom
sumber