android dev - Rilevamento del gesto di lancio sul layout della griglia




navigation drawer (16)

Ho leggermente modificato e riparato la soluzione da Thomas Fankhauser

L'intero sistema è costituito da due file, SwipeInterface e 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);

}

Rivelatore

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

}

è usato così:

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

E nell'implementazione Activity è necessario implementare i metodi da SwipeInterface e puoi scoprire su quale vista è stato chiamato l' evento di scorrimento .

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

Voglio ottenere il rilevamento dei gesti di fling funziona nella mia applicazione Android.

Quello che ho è un GridLayout che contiene 9 ImageView s. La fonte può essere trovata qui: Grid Layout di Romain Guys .

Quel file che prendo è tratto dall'applicazione Photostream di Romain Guy ed è stato adattato solo leggermente.

Per la semplice situazione dei clic, devo solo impostare onClickListener per ogni ImageView che aggiungo per essere l' activity principale che implementa View.OnClickListener . Sembra infinitamente più complicato implementare qualcosa che riconosca fling . Presumo che questo è perché potrebbe estendersi su views di views ?

  • Se la mia attività implementa OnGestureListener , non so come impostarla come listener di gesti per la Grid o per le visualizzazioni di Image che aggiungo.

    public class SelectFilterActivity extends Activity implements
       View.OnClickListener, OnGestureListener { ...
    
  • Se la mia attività implementa OnTouchListener allora non ho alcun metodo onFling da override (ha due eventi come parametri che mi permettono di determinare se l'avventura è stata degna di nota).

    public class SelectFilterActivity extends Activity implements
        View.OnClickListener, OnTouchListener { ...
    
  • Se GestureImageView una View personalizzata, come GestureImageView che estende ImageView , non so come dire all'attività che si è verificata GestureImageView dalla vista. In ogni caso, ho provato questo e i metodi non sono stati chiamati quando ho toccato lo schermo.

Ho davvero bisogno di un esempio concreto di questo lavoro attraverso le viste. Cosa, quando e come dovrei collegare questo listener ? Devo essere in grado di rilevare anche singoli clic.

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

È possibile posizionare una vista trasparente sulla parte superiore dello schermo per catturare gli oggetti?

Se scelgo di non inflate mie viste immagine figlio da XML, posso passare GestureDetector come parametro costruttore a una nuova sottoclasse di ImageView che creo?

Questa è l'attività molto semplice a cui sto cercando di far funzionare il rilevamento di fling : SelectFilterActivity (adattato dal photostream) .

Ho guardato queste fonti:

Niente ha funzionato per me finora e speravo in alcuni suggerimenti.


La mia versione della soluzione proposta da Thomas Fankhauser e Marek Sebera (non gestisce gli swip verticali):

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

}

Ho incorporato una classe più generica, ho preso la classe di Tomas e ho aggiunto un'interfaccia che inviava eventi alla tua attività o frammento. registrerà il listener sul costruttore, quindi assicurati di implementare l'interfaccia o di classificare un ClassCastException. l'interfaccia restituisce uno dei quattro final int definiti nella classe e restituirà la vista su cui è stato attivato.

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

}

So che è troppo tardi per rispondere, ma sto ancora postando Swipe Detection per ListView che Come usare Swipe Touch Listener in ListView Item .

Refrence: Exterminator13 (una delle risposte in questa pagina)

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

}

Chiamalo dalla tua classe di attività in questo modo:

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

E non dimenticare di implementare SwipeInterface che ti fornirà due metodi @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");
    }

A tutti: non dimenticare il caso MotionEvent.ACTION_CANCEL:

chiama in swipes del 30% senza ACTION_UP

ed è uguale a ACTION_UP in questo caso


C'è un'interfaccia integrata che puoi usare direttamente per tutti i gesti:
Ecco una spiegazione per un utente di livello base: Ci sono 2 importazioni fate attenzione nella scelta che entrambi siano diversi


Anche come un miglioramento minore.

Il motivo principale per il blocco try / catch è che e1 potrebbe essere nullo per il movimento iniziale. oltre a try / catch, include un test per null e return. simile al seguente

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

Una delle risposte sopra menziona la gestione della diversa densità di pixel, ma suggerisce il calcolo dei parametri di scorrimento a mano. Vale la pena notare che puoi effettivamente ottenere valori ragionevoli ridimensionati dal sistema usando la classe ViewConfiguration :

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)

Ho notato che l'uso di questi valori fa sì che la "sensazione" di fling sia più coerente tra l'applicazione e il resto del sistema.


Grazie a Code Shogun , il cui codice ho adattato alla mia situazione.

Lascia che la tua attività implementa OnClickListener come al solito:

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

Collega il tuo listener di gesti a tutte le viste che aggiungi al layout principale;

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

Guarda in soggezione quando vengono colpiti i metodi onFling override, sia onClick(View v) dell'attività e onFling del listener di gesti.

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

Il post "ballare" è facoltativo ma incoraggiato.


Lo faccio un po 'diverso, e ho scritto una classe extra di rivelatore che implementa View.onTouchListener

onCreate è semplicemente aggiungerlo al layout più basso come questo:

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

dove id.lowestLayout è id.xxx per la vista più bassa nella gerarchia di layout e lowestLayout è dichiarato come RelativeLayout

E poi c'è l'attuale classe di rilevatori di colpi:

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

}

Funziona davvero bene per me!


Ci sono molte informazioni eccellenti qui. Sfortunatamente un sacco di questo codice di elaborazione delle fiammate è sparsi su vari siti in vari stati di completamento, anche se si penserebbe che questo sia essenziale per molte applicazioni.

Mi sono preso il tempo necessario per creare un listener di fling che verifichi che siano soddisfatte le condizioni appropriate. Ho aggiunto un listener di follia di pagina che aggiunge ulteriori controlli per garantire che gli annunci soddisfino la soglia per gli annunci di pagina. Entrambi questi ascoltatori consentono di limitare facilmente gli attacchi sull'asse orizzontale o verticale. Puoi vedere come viene utilizzato in una vista per le immagini scorrevoli . Riconosco che le persone qui hanno fatto la maggior parte della ricerca --- l'ho appena messo insieme in una libreria utilizzabile.

Questi ultimi giorni rappresentano la mia prima pugnalata alla codifica su Android; aspettarsi molto di più a venire.


Questa domanda è ViewPager vecchia e nel luglio 2011 Google ha rilasciato il pacchetto di compatibilità, revisione 3) che include ViewPager che funziona con Android 1.6 verso l'alto. Le risposte GestureListener pubblicate per questa domanda non si sentono molto eleganti su Android. Se stai cercando il codice utilizzato per passare da una foto ViewPager nella Galleria Android o passare da una vista ViewPager nella nuova app Play Market, allora è sicuramente ViewPager .

Ecco alcuni link per maggiori informazioni:


I gesti sono quei movimenti sottili per attivare le interazioni tra il touch screen e l'utente. Dura per il tempo che intercorre tra il primo tocco sullo schermo e il punto in cui l'ultimo dito lascia la superficie.

Android ci fornisce una classe chiamata GestureDetector che consente di rilevare i gesti più comuni come il picchettamento verso il basso e verso l'alto, lo scorrimento verticale e orizzontale (lancio), la pressione lunga e breve, i doppi tocchi, ecc . e attacca gli ascoltatori a loro.

Fai in modo che la nostra classe Attività implementa GestureDetector.OnDoubleTapListener (per il rilevamento dei gesti con doppio tocco) e GestureDetector.OnGestureListener e implementa tutti i metodi astratti. Per ulteriori informazioni. è possibile visitare https://developer.android.com/training/gestures/detector.html . Courtesy

Per prova demo GestureDetectorDemo


C'è qualche proposta sul web (e su questa pagina) per usare ViewConfiguration. getScaledTouchSlop () per avere un valore ridimensionato dal dispositivo per SWIPE_MIN_DISTANCE .

getScaledTouchSlop() è inteso per la distanza della "soglia di scorrimento ", non per lo scorrimento. La distanza della soglia di scorrimento deve essere minore di una distanza di soglia di "swing tra le pagine". Ad esempio, questa funzione restituisce 12 pixel sul mio Samsung GS2, e gli esempi citati in questa pagina sono di circa 100 pixel.

Con API Level 8 (Android 2.2, Froyo), hai getScaledPagingTouchSlop() , progettato per lo scorrimento della pagina. Sul mio dispositivo, restituisce 24 (pixel). Quindi se sei su API Level <8, penso che "2 * getScaledTouchSlop() " dovrebbe essere la soglia di scorrimento "standard". Ma gli utenti della mia applicazione con schermi piccoli mi hanno detto che erano troppo pochi ... Come per la mia applicazione, puoi scorrere verticalmente e cambiare pagina orizzontalmente. Con il valore proposto, a volte cambiano la pagina anziché lo scorrimento.


Il codice del rilevatore di gesti swipe qui sopra è molto utile! Si potrebbe tuttavia voler rendere agnostica questa densità di densità utilizzando i seguenti valori relativi (REL_SWIPE) piuttosto che i valori assoluti (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);

Il problema qui è che setOnTabChangedListener non si setOnTabChangedListener quando si fa clic sulla scheda selezionata e se si imposta OnClickListener nella scheda, si perde il normale comportamento della scheda.

Quindi una soluzione semplice è mettere OnClickListener nella scheda, e al suo interno, imposta programmaticamente che questa è la scheda corrente.

Con TabHost :

getTabWidget().getChildAt(0).setOnClickListener(new View.OnClickListener() {
    @Override
    public void onClick(View v) {
        // custom code
        tabHost.setCurrentTab(0);                                    
    }
});

Con TabLayout

tabLayout.getTabAt(0)setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                    // custom code
                    TabLayout.Tab tab  = tabLayout.getTabAt(0);
                    tab.select();
                }
            }
        });




android listener gesture-recognition