terça-feira, 30 de outubro de 2012

Gesto de Swipe no Android

Olá povo,

Recentemente precisei implementar a detecção do gesto de swipe em uma aplicação iOS que estava desenvolvendo. Achei super fácil e resolvi pesquisar como fazer o mesmo no Android. Eis que achei a solução abaixo. (Não me lembro o post original, quem souber, posta um comentário pls).
public class MainActivity extends Activity 
  implements OnClickListener, OnTouchListener {

  private GestureDetector gestureDetector;
  private TextView txtResultado;
    
  @Override
  public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);
        
    txtResultado = 
      (TextView)findViewById(R.id.txtResultado);
        
    gestureDetector = 
      new GestureDetector(this, new DetectorDeGesto());
    
    // Apesar da linha abaixo não fazer nada, 
    // não funcionou sem...
    findViewById(R.id.raizLayout).
      setOnClickListener(this);
    findViewById(R.id.raizLayout).
      setOnTouchListener(this);
  }

  @Override
  public void onClick(View v) {
    Log.d("NGVL", "onclick");
  }  
    
  @Override
  public boolean onTouch(View v, MotionEvent event) {
    return gestureDetector.onTouchEvent(event);
  } 

  class DetectorDeGesto 
    extends SimpleOnGestureListener {
     
    private static final int DISTANCIA_MINIMA  = 120;
    private static final int DISTANCIA_MAXIMA  = 250;
    private static final int VELOCIDADE_MINIMA = 200;
     
    @Override
    public boolean onFling(MotionEvent e1, MotionEvent e2, 
      float velocityX, float velocityY) {
      try {
        boolean excedeuDistanciaEmY =
          Math.abs(e1.getY() - e2.getY()) 
          > DISTANCIA_MAXIMA;
               
        if (excedeuDistanciaEmY) return false;
                
        boolean velocidadeValida =
          Math.abs(velocityX) > VELOCIDADE_MINIMA;
                
        boolean swipeLeft = 
          e1.getX() - e2.getX() > DISTANCIA_MINIMA;
        boolean swipeRight =
          e2.getX() - e1.getX() > DISTANCIA_MINIMA;
                  
        // right to left swipe
        if(swipeLeft && velocidadeValida) {
          txtResultado.setText("Left Swipe");

        // left to right swipe
        }  else if (swipeRight && velocidadeValida) {
          txtResultado.setText("Right Swipe");
        }
      } catch (Exception e) {
      }
      return false;
    }
  }  
}
A classe SimpleOnGestureListener é uma classe básica do Android que consegue detectar diversos gestos simples como scroll, double tap, entre outros. Nossa classe DetectorDeGesto, herda dessa classe e sobrescreve o método onFling, que é chamado quando o usuário está deslizando o dedo sobre a tela (esse evento é armazenado em e2) e guarda a referência de quando o usuário pressionou o dedo sobre a tela inicialmente (armazenado em e1). Nesse método verificamos a direção que foi feito o swipe, bem como a velocidade que o movimento foi feito. As distâncias mínima e máxima para considerarmos o gesto válido, assim como a velocidade mínima estão definidas nas constantes da classe.
Nossa Activity implementa as interfaces View.OnClickListener e OnTouchListener. No método onTouch, delegamos o tratamento do evento de touch para o nosso detector de Gesto. Para que isso aconteça, no onCreate, criamos um GestureDetector (que é outra classe do próprio Android) passando o nosso detector de gestos. Em seguida, pegamos a referência da view que queremos tratar o evento de touch e setamos o onTouchListener e o onClickListener.
O arquivo de layout usado no projeto é mostrado abaixo:
<RelativeLayout 
  xmlns:android="http://schemas.android.com/apk/res/android"
  xmlns:tools="http://schemas.android.com/tools"
  android:id="@+id/raizLayout"
  android:layout_width="match_parent"
  android:layout_height="match_parent" >

  <TextView
    android:id="@+id/txtResultado"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:layout_centerHorizontal="true"
    android:layout_centerVertical="true"
    android:textSize="40dp"
    tools:context=".MainActivity" />
</RelativeLayout>
Pronto! É só rodar a aplicação e testar SWIPE pra esquerda e direita.

Qualquer dúvida, é só deixar seus comentários.

4br4ç05,
nglauber

2 comentários:

Marcos Baião disse...

NELSON PARABENS PELO POST.

MAS ME VE SE EU ENTENDI DIREITO. O USO DE onFling SÓ ME PERMITE DUAS "TELAS" POR ACTIVITY?

Nelson Glauber de Vasconcelos Leal disse...

Oi Marcos,

Você pode usar quantas telas quiser, basta fazer um controle. Você pode declarar um contador, onde ao fazer um swipe left, você incrementaria o valor e no swipe right diminuiria o valor.
Então baseado nesse contador você exibiria o conteúdo de acordo com o que você precisasse.

4br4ç05,
nglauber