Pertanyaan Fling gesture detection pada tata letak grid


Saya ingin mendapatkannya fling deteksi gerakan bekerja di aplikasi Android saya.

Apa yang saya miliki adalah a GridLayout yang berisi 9 ImageViews. Sumbernya dapat ditemukan di sini: Tata Letak Grid Romain Guys.

File yang saya ambil adalah dari Romain Guy Aplikasi photostream dan hanya sedikit diadaptasi.

Untuk situasi klik sederhana saya hanya perlu mengatur onClickListener untuk setiap ImageView Saya menambahkan untuk menjadi yang utama activity yang mengimplementasikan View.OnClickListener. Tampaknya jauh lebih rumit untuk mengimplementasikan sesuatu yang mengakui fling. Saya kira ini karena mungkin span views?

  • Jika aktivitas saya mengimplementasikan OnGestureListener Saya tidak tahu caranya tetapkan itu sebagai pendengar gestur untuk itu Grid atau Image memandang saya menambahkan.

    public class SelectFilterActivity extends Activity implements
       View.OnClickListener, OnGestureListener { ...
    
  • Jika aktivitas saya mengimplementasikan OnTouchListener maka saya tidak punya onFling metode untuk override (memiliki dua peristiwa sebagai parameter yang memungkinkan saya untuk menentukan apakah fling itu penting).

    public class SelectFilterActivity extends Activity implements
        View.OnClickListener, OnTouchListener { ...
    
  • Jika saya membuat kebiasaan View, suka GestureImageView yang meluas ImageView Saya tidak tahu bagaimana cara mengatakan aktivitas itu a fling telah terjadi dari tampilan. Dalam hal apapun, saya mencoba ini dan metode tidak dipanggil ketika saya menyentuh layar.

Saya benar-benar hanya membutuhkan contoh konkret dari ini bekerja di seluruh 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 inflate Pandangan gambar anak saya dari XML dapat saya lewati GestureDetector sebagai parameter konstruktor ke subkelas baru ImageView yang saya buat?

Ini adalah kegiatan yang sangat sederhana yang saya coba dapatkan fling deteksi berfungsi untuk: SelectFilterActivity (Diadaptasi dari photostream).

Saya telah melihat sumber-sumber ini:

Tidak ada yang berhasil bagi saya sejauh ini dan saya berharap untuk beberapa petunjuk.


997
2018-06-01 23:35


asal


Jawaban:


Terimakasih untuk Kode Shogun, kode siapa saya beradaptasi dengan situasi saya.

Biarkan aktivitas Anda terapkanOnClickListener seperti 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 penuh kekaguman saat metode yang ditimpa Anda terpukul, keduanya onClick(View v) dari aktivitas dan onFling dari pendengar gerakan.

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

Tarikan postingan 'fling' adalah opsional tetapi didorong.


774
2018-04-20 17:26



Salah satu jawaban di atas menyebutkan penanganan kepadatan piksel yang berbeda tetapi menyarankan menghitung parameter gesek dengan tangan. Perlu dicatat bahwa Anda benar-benar dapat memperoleh skala, nilai wajar dari sistem menggunakan ViewConfiguration kelas:

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" dari fling menjadi lebih konsisten antara aplikasi dan sisa sistem.


203
2018-04-21 10:24



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

onCreatehanya menambahkannya 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 layout dan lowestLayout dideklarasikan sebagai RelativeLayout

Dan kemudian ada kelas detektor aktivitas geser 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 untukku!


140
2018-01-10 16:11



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

}

itu digunakan seperti ini:

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

Dan dalam mengimplementasikan Activity Anda perlu menerapkan metode dari SwipeInterface, dan Anda dapat mengetahui di mana Lihat Acara Swipe telah dipanggil.

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

90
2018-02-18 09:45



Kode pendeteksi gerakan geseran di atas sangat berguna! Namun Anda mungkin ingin membuat keragaman solusi ini agnostik dengan menggunakan nilai-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);

61
2017-07-18 01:00



Versi solusi saya yang 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;
    }

}

32
2018-04-23 19:54



Pertanyaan ini agak lama dan pada Juli 2011 Google merilis Paket Kompatibilitas, revisi 3) yang termasuk ViewPager yang berfungsi dengan Android 1.6 ke atas. Itu GestureListener jawaban yang diposting untuk pertanyaan ini tidak terasa sangat elegan di Android. Jika Anda mencari kode yang digunakan untuk beralih antar-foto di Galeri Android atau beralih tampilan di aplikasi Play Market baru, itu pasti ViewPager.

Berikut ini beberapa tautan untuk info lebih lanjut:


21
2018-04-05 14:28



Ada antarmuka bawaan yang dapat Anda gunakan secara langsung untuk semua isyarat:
Berikut ini penjelasan untuk pengguna tingkat dasar: enter image description here Ada 2 impor berhati-hati dalam memilih bahwa keduanya berbeda enter image description here enter image description here


14
2018-04-12 21:14