Android: Gesten
Willemers Informatik-Ecke

Mit Android ist es möglich, verschiedene Gesten zu verarbeiten. Als Beispiel werden auf dieser Seite das Wischen über den Bildschirm oder das doppelte Tappen auf den Schirm ausgewählt.

Das Programm fängt die beiden Ereignisse und gibt diese auf fünf TextViews aus, die als tv, velx, vely, ev1 und ev2 in der Layout-XML-Datei definiert sein müssen.

Gesten sind TouchEvents

Gesten sind Sonderfälle der Touch-Ereignisse. Die Berührung einer Activity lässt sich einfach fangen, indem die Activity die Methode onTouchEvent überschreibt. Dazu muss kein Listener implementiert werden.
    @Override
    public boolean onTouchEvent(MotionEvent event) {
        // ...
        return super.onTouchEvent(event);
    }
Durch das Auswerten der Ereignisse könnten die Gesten erkannt werden. Allerdings ist das deutlich mühsamer, als einen GestureDetector einzusetzen. Dieser ist darauf spezialisiert, Gesten zu erkennen. Er übernimmt die TouchEvents und wertet sie aus.

Allerdings ist er nicht der einzige Interessent für die Touch-Ereignisse. Auch eine ScrollView wertet die Touch-Ereignisse aus und kommt dann der Gesten-Erkennung empfindlich in die Quere. Darum kann man nur eines von beiden einsetzen.

GestureDetector, der Gestenspezialist

Der GestureDetector wird in der Methode onTouchEvent eingeschoben. Über ihn wird das Touch-Ereignis weitergeleitet.

    GestureDetector detector = null;
    // ...
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        // ...
        this.detector = new GestureDetector(this, new MyGestureListener());
    }

    @Override
    public boolean onTouchEvent(MotionEvent event) {
        this.detector.onTouchEvent(event);
        return super.onTouchEvent(event);
    }
Bei der Erzeugung des GestureDetector muss ein eigener GestureListener erstellt werden, der dann die Gesten auswertet.

GestureListener

Die eigentlichen Gestenereignisse werden in der Klasse MyGestureListener abgearbeitet, die dazu SimpleOnGestureListener erweitert.

Dazu muss die Methode onDraw implementiert werden. Weitere Methoden können überschrieben werden, um bestimmte Gesten zu empfangen.

Alles zusammen

package de.willemer.gesten;

import androidx.appcompat.app.AppCompatActivity;

import android.os.Bundle;
import android.util.Log;
import android.view.GestureDetector;
import android.view.MotionEvent;
import android.view.View;
import android.widget.TextView;

public class MainActivity extends AppCompatActivity {

    private static final String TAG = "Gesten";
    GestureDetector detector = null;
    TextView tv1, tv2, tvx, tvy, tv;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        tv = (TextView) findViewById(R.id.tv);
        tvx = (TextView) findViewById(R.id.velx);
        tvy = (TextView) findViewById(R.id.vely);
        tv1 = (TextView) findViewById(R.id.ev1);
        tv2 = (TextView) findViewById(R.id.ev2);
        this.detector = new GestureDetector(this, new MyGestureListener());
    }

    @Override
    public boolean onTouchEvent(MotionEvent event) {
        this.detector.onTouchEvent(event);
        return super.onTouchEvent(event);
    }


    class MyGestureListener extends GestureDetector.SimpleOnGestureListener {
        @Override
        public boolean onDown(MotionEvent ev) {
            Log.d(TAG, "onDown ist eingetroffen");
            return true; // muss true sein
        }
        @Override
        public boolean onFling(MotionEvent ev1, MotionEvent ev2, float velX, float velY) {
            tv.setText("Fling Event ist eingetroffen");
            tvx.setText(""+velX);
            tvy.setText(""+velY);
            tv1.setText(ev1.toString());
            tv2.setText(ev2.toString());
            return true;
        }
        @Override
        public boolean onDoubleTap(MotionEvent ev) {
            tv.setText("DoubleTap ist eingetroffen");
            tvx.setText("");
            tvy.setText("");
            tv1.setText("");
            tv2.setText(ev.toString());
            return true;
        }
    }
}
Das Wischen wird durch onFling gefangen. Die beiden float-Parameter geben an, wie stark in X- bzw. Y-Richtung gewischt wurde. Man muss die Werte ein wenig ins Verhältnis setzen, um die korrekte Richtung zu ermitteln. Negative Werte gehen nach links bzw. nach oben.