4. Februar 2013

Android: Gestenerkennung (Swipe)

Die Bedienung eines Smartphones oder Tablets fühlt sich besonders elegant an, wenn die jeweilige App Gesten zur Bedienung anbietet. Dieser Post soll die Gestenerkennung von Wischgesten unter Android rudimentär erklären. Eine Übersicht über alle, von den Android-Entwicklern offiziell vorgesehenen Gesten, findet man unter http://developer.android.com/design/patterns/gestures.html. Dieses Beispiel soll sich dabei um Swipe-Gesten drehen, also eine Wischbewegung in eine bestimmte Richtung, wie sie etwa genutzt werden kann, um zwischen mehreren Seiten zu blättern oder eine Sidebar einzublenden.

Die Gestenerkennung ist innerhalb einer Activity oder einer View möglich. Für die Erkennung bietet die Android-API die Klasse android.view.GestureDetector an. Außerdem muss das Interface android.view.GestureDetector.OnGestureListener implementiert werden, um auf erkannte Gesten reagieren zu können. Für eine beispielhafte Activity könnte die Erkennung einer Swipe-Geste (in diesem Fall von links nach rechts) wie folgt aussehen:
 public class MainActivity extends Activity implements OnGestureListener {  
     
   private GestureDetector gestureDetector;   
   
   @Override  
   public void onCreate(Bundle savedInstanceState) {  
     super.onCreate(savedInstanceState);  
     setContentView(R.layout.activity_main);  
       
     gestureDetector = new GestureDetector(this,this);  
   }  
   
   @Override   
   public boolean onTouchEvent (MotionEvent event) {   
     this.gestureDetector.onTouchEvent(event);  
     return super.onTouchEvent(event);  
   }  
   
   @Override  
   public boolean onDown(MotionEvent event) {   
     return false;  
   }  
   
   @Override  
   public boolean onFling(MotionEvent event1, MotionEvent event2,   
       float velocityX, float velocityY) {  
     if (event1.getX() < event2.getX()) {  
       TextView textView = (TextView) findById(R.id.textView);  
       textView.setText("detected swipe gesture");  
       return true;
     }  
     return false;  
   }  
   
   @Override  
   public void onLongPress(MotionEvent event) {  
        
   }  
   
   @Override  
   public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX,  
       float distanceY) {  
     return false;  
   }  
   
   @Override  
   public void onShowPress(MotionEvent event) {  
       
   }  
   
   @Override  
   public boolean onSingleTapUp(MotionEvent event) {  
     return false;  
   }  
   
   @Override  
   public boolean onDoubleTap(MotionEvent event) {  
     return false;  
   }  
   
   @Override  
   public boolean onDoubleTapEvent(MotionEvent event) {  
     return false;  
   }  
   
   @Override  
   public boolean onSingleTapConfirmed(MotionEvent event) {  
     return false;  
   }  
   
 }  
Die Instanz des GestureDetectors wird hierbei in der onCreate-Methode der Activity erzeugt, indem der Context, in diesem Fall die Activity selbst, sowie die entsprechende Listener-Implementation, in diesem Fall auch die Activity selbst, übergeben wird.

Die Activity, die in diesem Fall die Schnittstelle OnGestureListener implementiert, wird dadurch um einige Methoden erweitert. In diesem Beispiel ist nur die onFling-Methode, die für die Erkennung von Wischbewegungen gedacht ist, relevant. Der Methode werden, neben zwei Werten für die horizontale und vertikale Wischgeschwindigkeit, auch jeweils ein MotionEvent für den Start und das Ende der Wischbewegung als Parameter übergeben. Über diese MotionEvents lässt sich die Wischrichtung ermitteln. Handelt es sich um eine horizontale Swipe-Geste von links nach rechts, so wird in diesem Beispiel der Text einer TextView geändert.

Außerdem ist zu beachten, dass die Activity die onTouchEvent-Methode überschreiben muss, um das jeweilige TouchEvent an den GestureDetector und die Superklasse weiterzuleiten.

Die zugehörige XML Layout Datei zu diesem Beispiel sieht wie folgt aus:
 <?xml version="1.0" encoding="utf-8"?>  
 <LinearLayout  
   android:layout_width="match_parent"  
   android:layout_height="match_parent"  
   android:orientation="vertical" >  
   
   <TextView  
     android:id="@+id/textView"  
     android:layout_width="wrap_content"  
     android:layout_height="wrap_content"  
     android:text="no gesture detected" />  
   
 </LinearLayout>  
Ein Problem der hier beschriebenen Vorgehensweise kann sein, dass Gesten nur erkannt werden, wenn sie auf dem Hintergrund der Activity ausgeführt werden. Beinhaltet die Activity viele Komponenten wie beispielsweise Buttons, so werden darauf ausgeführte Gesten nicht erkannt. Die Problematik kann durch die Verwendung einer so genannten GestureOverlayView gelöst werden, die transparent über alle anderen Views gelegt wird um die Eingaben abzufangen. Auf diese Möglichkeit soll in einem weiterführenden Post eingegangen werden.

Nachtrag vom 8. Februar 2013: Der Post über oben erwähnte Möglichkeit zur Verwendung einer "GestureOverlayView" ist von nun an hier zu finden.

Keine Kommentare:

Kommentar veröffentlichen