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:
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:
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 vonImageView
hinzu:_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 ImageView
darf, 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:
Solange der Benutzer die ImageView
touchiert, wird Touch Begins in TextView
angezeigt. Wenn der Benutzer den nicht mehr berührt ImageView
, wird die Meldung Touch Ends im TextView
angezeigt, wie im folgenden Screenshot gezeigt:
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
GestureRecognizer
hinzu. 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 einenImageView
hinzu. An diesem Punkt wird der Code immer noch nicht kompiliert. Wir müssen die -KlasseMyScaleListener
erstellen, die beim Ändern der Größe hilftImageView
, 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 dieImageView
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 anheftenImageView
kann. Wir fügen eine Klasse namens hinzuMyScaleListener
. Diese Klasse lauscht auf die Skalierungsereignisse, die von Android ausgelöst werden, wenn der Benutzer anhefttImageView
. Fügen Sie die folgende innere Klasse hinzuGestureRecognizerView
. Diese Klasse ist einScaleGesture.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, istOnTouchEvent
. 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.OnTouchEvent
von 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:
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:
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 instanziierenGestureOverlayView
und als Stammansicht der Aktivität festzulegen. Außerdem weisen wir demGesturePerformed
Ereignis vonGestureOverlayView
einen Ereignishandler zu. Als Nächstes wird die zuvor erstellte Layoutdatei aufgeblasen und als untergeordnete Ansicht desGestureOverlayView
hinzugefü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 eineGestureOverlayView
Geste erkannt wird, ruft es diese Methode zurück. Das erste, was wir versuchen, einIList<Prediction>
Objekt abzurufen, das der Geste entspricht, indem wir aufrufen_gestureLibrary.Recognize()
. Wir verwenden ein wenig LINQ, um das abzurufen, dasPrediction
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:
Zeichnen Sie nun ein Häkchen auf dem Bildschirm, und die angezeigte Bitmap sollte in etwa wie in den nächsten Screenshots dargestellt aussehen:
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:
Sie wissen jetzt, wie Sie Toucheingaben und Gesten mithilfe von Xamarin.Android in eine Android-Anwendung integrieren können.