Exemplarische Vorgehensweise: Verwenden von Touch in Android

Sehen Sie sich an, wie Sie die Konzepte aus dem vorherigen Abschnitt in einer funktionierenden Anwendung verwenden. Wir erstellen eine Anwendung mit vier Aktivitäten. Die erste Aktivität ist ein Menü oder eine Schalttafel, die die anderen Aktivitäten startet, um die verschiedenen APIs zu veranschaulichen. Der folgende Screenshot zeigt die aktivität Standard:

Beispielfoto mit der Schaltfläche

Im ersten Aktivitätsbeispiel wird gezeigt, wie Ereignishandler zum Berühren der Ansichten verwendet werden. Die Gestenerkennungsaktivität veranschaulicht, wie Ereignisse unterklassig Android.View.Views und behandelt werden, und zeigt, wie Gesten mit Pinch-Gesten behandelt werden. Die dritte und letzte Aktivität, Benutzerdefinierte Geste, zeigt, wie benutzerdefinierte Gesten verwendet werden. Um das Nachverfolgen und Auffangen zu erleichtern, werden wir diese exemplarische Vorgehensweise in Abschnitte unterteilen, wobei sich jeder Abschnitt auf eine der Aktivitäten konzentriert.

Touchbeispielaktivität

  • Öffnen Sie das Projekt TouchWalkthrough_Start. Die MainActivity wird los – es liegt an uns, das Touchverhalten in der Aktivität zu implementieren. Wenn Sie die Anwendung ausführen und auf TouchBeispiel klicken, sollte die folgende Aktivität gestartet werden:

    Screenshot der Aktivität mit angezeigten Touch Begins

  • Nachdem wir nun bestätigt haben, dass die Aktivität gestartet wird, öffnen Sie die Datei TouchActivity.cs , und fügen Sie einen Handler für das Touch Ereignis von ImageViewhinzu:

    _touchMeImageView.Touch += TouchMeImageViewOnTouch;
    
  • Fügen Sie als Nächstes touchActivity.cs die folgende Methode hinzu:

    private void TouchMeImageViewOnTouch(object sender, View.TouchEventArgs touchEventArgs)
    {
        string message;
        switch (touchEventArgs.Event.Action & MotionEventActions.Mask)
        {
            case MotionEventActions.Down:
            case MotionEventActions.Move:
            message = "Touch Begins";
            break;
    
            case MotionEventActions.Up:
            message = "Touch Ends";
            break;
    
            default:
            message = string.Empty;
            break;
        }
    
        _touchInfoTextView.Text = message;
    }
    

Beachten Sie im obigen Code, dass wir die Move Aktion und Down die Aktion gleich behandeln. Dies liegt daran, dass der Benutzer, obwohl der Benutzer seinen Finger nicht vom Finger heben ImageViewdarf, sich bewegen kann oder sich der vom Benutzer ausgeübte Druck ändert. Diese Arten von Änderungen generieren eine Move Aktion.

Jedes Mal, wenn der Benutzer den berührt ImageView, wird das Touch Ereignis ausgelöst, und unser Handler zeigt die Meldung Touch Begins auf dem Bildschirm an, wie im folgenden Screenshot gezeigt:

Screenshot der Aktivität mit Touch Begins

Solange der Benutzer die ImageViewtouchiert, wird Touch Begins in TextViewangezeigt. Wenn der Benutzer den nicht mehr berührt ImageView, wird die Meldung Touch Ends im TextViewangezeigt, wie im folgenden Screenshot gezeigt:

Screenshot der Aktivität mit Touch Ends

Gestenerkennungsaktivität

Jetzt können Sie die Gestenerkennungsaktivität implementieren. In dieser Aktivität wird veranschaulicht, wie eine Ansicht auf den Bildschirm gezogen wird, und eine Möglichkeit zum Implementieren von Pinch-to-Zoom veranschaulicht.

  • Fügen Sie der Anwendung eine neue Aktivität mit dem Namen GestureRecognizerhinzu. Bearbeiten Sie den Code für diese Aktivität so, dass er dem folgenden Code ähnelt:

    public class GestureRecognizerActivity : Activity
    {
        protected override void OnCreate(Bundle bundle)
        {
            base.OnCreate(bundle);
            View v = new GestureRecognizerView(this);
            SetContentView(v);
        }
    }
    
  • Fügen Sie dem Projekt eine neue Android-Ansicht hinzu, und nennen Sie sie GestureRecognizerView. Fügen Sie dieser Klasse die folgenden Variablen hinzu:

    private static readonly int InvalidPointerId = -1;
    
    private readonly Drawable _icon;
    private readonly ScaleGestureDetector _scaleDetector;
    
    private int _activePointerId = InvalidPointerId;
    private float _lastTouchX;
    private float _lastTouchY;
    private float _posX;
    private float _posY;
    private float _scaleFactor = 1.0f;
    
  • Fügen Sie den folgenden Konstruktor hinzu GestureRecognizerView. Dieser Konstruktor fügt unserer Aktivität einen ImageView hinzu. An diesem Punkt wird der Code immer noch nicht kompiliert. Wir müssen die -Klasse MyScaleListener erstellen, die beim Ändern der Größe hilft ImageView , wenn der Benutzer ihn anheften kann:

    public GestureRecognizerView(Context context): base(context, null, 0)
    {
        _icon = context.Resources.GetDrawable(Resource.Drawable.Icon);
        _icon.SetBounds(0, 0, _icon.IntrinsicWidth, _icon.IntrinsicHeight);
        _scaleDetector = new ScaleGestureDetector(context, new MyScaleListener(this));
    }
    
  • Um das Bild für unsere Aktivität zu zeichnen, müssen wir die Methode der OnDraw View-Klasse überschreiben, wie im folgenden Codeausschnitt gezeigt. Mit diesem Code wird die ImageView an die durch _posX und _posY angegebene Position verschoben und die Größe des Bilds entsprechend dem Skalierungsfaktor geändert:

    protected override void OnDraw(Canvas canvas)
    {
        base.OnDraw(canvas);
        canvas.Save();
        canvas.Translate(_posX, _posY);
        canvas.Scale(_scaleFactor, _scaleFactor);
        _icon.Draw(canvas);
        canvas.Restore();
    }
    
  • Als Nächstes müssen wir die variable instance _scaleFactor aktualisieren, da der Benutzer die anheften ImageViewkann. Wir fügen eine Klasse namens hinzu MyScaleListener. Diese Klasse lauscht auf die Skalierungsereignisse, die von Android ausgelöst werden, wenn der Benutzer anheftt ImageView. Fügen Sie die folgende innere Klasse hinzu GestureRecognizerView. Diese Klasse ist ein ScaleGesture.SimpleOnScaleGestureListener. Diese Klasse ist eine Komfortklasse, die Listener unterklassen können, wenn Sie an einer Teilmenge von Gesten interessiert sind:

    private class MyScaleListener : ScaleGestureDetector.SimpleOnScaleGestureListener
    {
        private readonly GestureRecognizerView _view;
    
        public MyScaleListener(GestureRecognizerView view)
        {
            _view = view;
        }
    
        public override bool OnScale(ScaleGestureDetector detector)
        {
            _view._scaleFactor *= detector.ScaleFactor;
    
            // put a limit on how small or big the image can get.
            if (_view._scaleFactor > 5.0f)
            {
                _view._scaleFactor = 5.0f;
            }
            if (_view._scaleFactor < 0.1f)
            {
                _view._scaleFactor = 0.1f;
            }
    
            _view.Invalidate();
            return true;
        }
    }
    
  • Die nächste Methode, in die wir überschreiben GestureRecognizerView müssen, ist OnTouchEvent. Der folgende Code listet die vollständige Implementierung dieser Methode auf. Es gibt hier viel Code, also lassen Sie uns eine Minute zeit und schauen, was hier vor sich geht. Das erste, was diese Methode tut, ist, das Symbol bei Bedarf zu skalieren. Dies wird durch Aufrufen _scaleDetector.OnTouchEventvon behandelt. Als Nächstes versuchen wir herauszufinden, welche Aktion diese Methode genannt wird:

    • Wenn der Benutzer den Bildschirm mit berührt hat, zeichnen wir die X- und Y-Positionen und die ID des ersten Zeigers auf, der den Bildschirm berührt hat.

    • Wenn der Benutzer seine Toucheingabe auf dem Bildschirm verschoben hat, erfahren wir, wie weit der Benutzer den Zeiger bewegt hat.

    • Wenn der Benutzer seinen Finger vom Bildschirm gehoben hat, beenden wir die Nachverfolgung der Gesten.

    public override bool OnTouchEvent(MotionEvent ev)
    {
        _scaleDetector.OnTouchEvent(ev);
    
        MotionEventActions action = ev.Action & MotionEventActions.Mask;
        int pointerIndex;
    
        switch (action)
        {
            case MotionEventActions.Down:
            _lastTouchX = ev.GetX();
            _lastTouchY = ev.GetY();
            _activePointerId = ev.GetPointerId(0);
            break;
    
            case MotionEventActions.Move:
            pointerIndex = ev.FindPointerIndex(_activePointerId);
            float x = ev.GetX(pointerIndex);
            float y = ev.GetY(pointerIndex);
            if (!_scaleDetector.IsInProgress)
            {
                // Only move the ScaleGestureDetector isn't already processing a gesture.
                float deltaX = x - _lastTouchX;
                float deltaY = y - _lastTouchY;
                _posX += deltaX;
                _posY += deltaY;
                Invalidate();
            }
    
            _lastTouchX = x;
            _lastTouchY = y;
            break;
    
            case MotionEventActions.Up:
            case MotionEventActions.Cancel:
            // We no longer need to keep track of the active pointer.
            _activePointerId = InvalidPointerId;
            break;
    
            case MotionEventActions.PointerUp:
            // check to make sure that the pointer that went up is for the gesture we're tracking.
            pointerIndex = (int) (ev.Action & MotionEventActions.PointerIndexMask) >> (int) MotionEventActions.PointerIndexShift;
            int pointerId = ev.GetPointerId(pointerIndex);
            if (pointerId == _activePointerId)
            {
                // This was our active pointer going up. Choose a new
                // action pointer and adjust accordingly
                int newPointerIndex = pointerIndex == 0 ? 1 : 0;
                _lastTouchX = ev.GetX(newPointerIndex);
                _lastTouchY = ev.GetY(newPointerIndex);
                _activePointerId = ev.GetPointerId(newPointerIndex);
            }
            break;
    
        }
        return true;
    }
    
  • Führen Sie nun die Anwendung aus, und starten Sie die Gestenerkennungsaktivität. Beim Starten sollte der Bildschirm in etwa wie der folgende Screenshot aussehen:

    Gestenerkennungsstartbildschirm mit Android-Symbol

  • Berühren Sie nun das Symbol, und ziehen Sie es auf dem Bildschirm. Versuchen Sie die Geste zum Zoomen. Irgendwann kann Ihr Bildschirm etwa wie der folgende Screenshot aussehen:

    Das Symbol

An dieser Stelle sollten Sie sich auf die Schulter klopfen: Sie haben gerade eine Pinch-to-Zoom-Anwendung in einer Android-Anwendung implementiert! Machen Sie eine kurze Pause und können Sie mit der dritten und letzten Aktivität in dieser exemplarischen Vorgehensweise fortfahren – mit benutzerdefinierten Gesten.

Benutzerdefinierte Gestenaktivität

Der letzte Bildschirm in dieser exemplarischen Vorgehensweise verwendet benutzerdefinierte Gesten.

Für diese exemplarische Vorgehensweise wurde die Gestenbibliothek bereits mithilfe des Gestentools erstellt und dem Projekt in der Datei Resources/raw/gestures hinzugefügt. Mit diesem Bisschen Housekeeping können Sie mit der letzten Aktivität in der exemplarischen Vorgehensweise beginnen.

  • Fügen Sie dem Projekt eine Layoutdatei mit dem Namen custom_gesture_layout.axml mit dem folgenden Inhalt hinzu. Das Projekt enthält bereits alle Images im Ordner Ressourcen :

    <?xml version="1.0" encoding="utf-8"?>
    <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
        android:orientation="vertical"
        android:layout_width="match_parent"
        android:layout_height="match_parent">
        <LinearLayout
            android:layout_width="match_parent"
            android:layout_height="0dp"
            android:layout_weight="1" />
        <ImageView
            android:src="@drawable/check_me"
            android:layout_width="match_parent"
            android:layout_height="0dp"
            android:layout_weight="3"
            android:id="@+id/imageView1"
            android:layout_gravity="center_vertical" />
        <LinearLayout
            android:layout_width="match_parent"
            android:layout_height="0dp"
            android:layout_weight="1" />
    </LinearLayout>
    
  • Fügen Sie als Nächstes dem Projekt eine neue Aktivität hinzu, und nennen Sie sie CustomGestureRecognizerActivity.cs. Fügen Sie der Klasse zwei instance Variablen hinzu, wie in den folgenden beiden Codezeilen gezeigt:

    private GestureLibrary _gestureLibrary;
    private ImageView _imageView;
    
  • Bearbeiten Sie die OnCreate Methode dieser Aktivität so, dass sie dem folgenden Code ähnelt. Nehmen wir uns eine Minute Zeit, um zu erklären, was in diesem Code vor sich geht. Das erste, was wir tun, ist, ein instanziieren GestureOverlayView und als Stammansicht der Aktivität festzulegen. Außerdem weisen wir dem GesturePerformed Ereignis von GestureOverlayVieweinen Ereignishandler zu. Als Nächstes wird die zuvor erstellte Layoutdatei aufgeblasen und als untergeordnete Ansicht des GestureOverlayViewhinzugefügt. Der letzte Schritt besteht darin, die Variable _gestureLibrary zu initialisieren und die Gestendatei aus den Anwendungsressourcen zu laden. Wenn die Gestendatei aus irgendeinem Grund nicht geladen werden kann, kann diese Aktivität nicht viel tun, sodass sie heruntergefahren wird:

    protected override void OnCreate(Bundle bundle)
    {
        base.OnCreate(bundle);
    
        GestureOverlayView gestureOverlayView = new GestureOverlayView(this);
        SetContentView(gestureOverlayView);
        gestureOverlayView.GesturePerformed += GestureOverlayViewOnGesturePerformed;
    
        View view = LayoutInflater.Inflate(Resource.Layout.custom_gesture_layout, null);
        _imageView = view.FindViewById<ImageView>(Resource.Id.imageView1);
        gestureOverlayView.AddView(view);
    
        _gestureLibrary = GestureLibraries.FromRawResource(this, Resource.Raw.gestures);
        if (!_gestureLibrary.Load())
        {
            Log.Wtf(GetType().FullName, "There was a problem loading the gesture library.");
            Finish();
        }
    }
    
  • Das Letzte, was wir tun müssen, um die -Methode GestureOverlayViewOnGesturePerformed zu implementieren, wie im folgenden Codeausschnitt gezeigt. Wenn eine GestureOverlayView Geste erkannt wird, ruft es diese Methode zurück. Das erste, was wir versuchen, ein IList<Prediction> Objekt abzurufen, das der Geste entspricht, indem wir aufrufen _gestureLibrary.Recognize(). Wir verwenden ein wenig LINQ, um das abzurufen, das Prediction die höchste Punktzahl für die Geste aufweist.

    Wenn keine übereinstimmende Geste mit einer ausreichend hohen Bewertung vorhanden ist, wird der Ereignishandler beendet, ohne etwas zu tun. Andernfalls überprüfen wir den Namen der Vorhersage und ändern das angezeigte Bild basierend auf dem Namen der Geste:

    private void GestureOverlayViewOnGesturePerformed(object sender, GestureOverlayView.GesturePerformedEventArgs gesturePerformedEventArgs)
    {
        IEnumerable<Prediction> predictions = from p in _gestureLibrary.Recognize(gesturePerformedEventArgs.Gesture)
        orderby p.Score descending
        where p.Score > 1.0
        select p;
        Prediction prediction = predictions.FirstOrDefault();
    
        if (prediction == null)
        {
            Log.Debug(GetType().FullName, "Nothing seemed to match the user's gesture, so don't do anything.");
            return;
        }
    
        Log.Debug(GetType().FullName, "Using the prediction named {0} with a score of {1}.", prediction.Name, prediction.Score);
    
        if (prediction.Name.StartsWith("checkmark"))
        {
            _imageView.SetImageResource(Resource.Drawable.checked_me);
        }
        else if (prediction.Name.StartsWith("erase", StringComparison.OrdinalIgnoreCase))
        {
            // Match one of our "erase" gestures
            _imageView.SetImageResource(Resource.Drawable.check_me);
        }
    }
    
  • Führen Sie die Anwendung aus, und starten Sie die Aktivität Benutzerdefinierte Gestenerkennung. Er sollte etwa wie der folgende Screenshot aussehen:

    Screenshot mit

    Zeichnen Sie nun ein Häkchen auf dem Bildschirm, und die angezeigte Bitmap sollte in etwa wie in den nächsten Screenshots dargestellt aussehen:

    Gezeichnetes Häkchen, Häkchen erkannt

    Zeichnen Sie schließlich einen Scribble auf dem Bildschirm. Das Kontrollkästchen sollte wie in den folgenden Screenshots gezeigt wieder auf das ursprüngliche Bild geändert werden:

    Scribble auf dem Bildschirm, Originalbild wird angezeigt

Sie wissen jetzt, wie Sie Toucheingaben und Gesten mithilfe von Xamarin.Android in eine Android-Anwendung integrieren können.