Procédure pas à pas - Utilisation de Touch dans Android
Voyons comment utiliser les concepts de la section précédente dans une application de travail. Nous allons créer une application avec quatre activités. La première activité sera un menu ou un commutateur qui lancera les autres activités pour illustrer les différentes API. La capture d’écran suivante montre l’activité principale :
La première activité, l’exemple tactile, montre comment utiliser des gestionnaires d’événements pour toucher les vues. L’activité Gesture Recognizer montre comment sous-classer Android.View.Views
et gérer les événements, ainsi que comment gérer les mouvements de pincement. La troisième et dernière activité, Custom Gesture, montre comment utiliser des mouvements personnalisés. Pour faciliter le suivi et l’absorption, nous allons interrompre cette procédure pas à pas dans les sections, chaque section se concentrant sur l’une des activités.
Activité d’exemple tactile
Ouvrez le projet TouchWalkthrough_Start. MainActivity est tout à fait prêt à aller : c’est à nous d’implémenter le comportement tactile dans l’activité. Si vous exécutez l’application et cliquez sur Touch Sample, l’activité suivante doit démarrer :
Maintenant que nous avons confirmé que l’activité démarre, ouvrez le fichier TouchActivity.cs et ajoutez un gestionnaire pour l’événement
Touch
duImageView
:_touchMeImageView.Touch += TouchMeImageViewOnTouch;
Ensuite, ajoutez la méthode suivante à TouchActivity.cs :
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; }
Notez dans le code ci-dessus que nous traitons les actions et Down
les Move
mêmes. Cela est dû au fait que même si l’utilisateur peut ne pas lever son doigt, ImageView
il peut se déplacer ou la pression exercée par l’utilisateur peut changer. Ces types de modifications génèrent une Move
action.
Chaque fois que l’utilisateur touche, ImageView
l’événement Touch
est déclenché et notre gestionnaire affiche le message Touch Begins à l’écran, comme illustré dans la capture d’écran suivante :
Tant que l’utilisateur touche la ImageView
touche, Touch Begins s’affiche dans le TextView
. Lorsque l’utilisateur ne touche ImageView
plus, le message touch ends s’affiche dans la TextView
capture d’écran suivante :
Activité de reconnaissance de mouvement
Implémente maintenant l’activité Gesture Recognizer. Cette activité montre comment faire glisser une vue autour de l’écran et illustrer une façon d’implémenter un pincement à zoom.
Ajoutez une nouvelle activité à l’application appelée
GestureRecognizer
. Modifiez le code de cette activité afin qu’il ressemble au code suivant :public class GestureRecognizerActivity : Activity { protected override void OnCreate(Bundle bundle) { base.OnCreate(bundle); View v = new GestureRecognizerView(this); SetContentView(v); } }
Ajoutez une nouvelle vue Android au projet et nommez-le
GestureRecognizerView
. Ajoutez les variables suivantes à cette classe :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;
Ajoutez le constructeur suivant à
GestureRecognizerView
. Ce constructeur ajoute uneImageView
à notre activité. À ce stade, le code ne sera toujours pas compilé : nous devons créer la classeMyScaleListener
qui vous aidera à redimensionner leImageView
moment où l’utilisateur le pince :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)); }
Pour dessiner l’image sur notre activité, nous devons remplacer la
OnDraw
méthode de la classe View, comme indiqué dans l’extrait de code suivant. Ce code déplace laImageView
position spécifiée_posX
et_posY
redimensionne l’image en fonction du facteur de mise à l’échelle :protected override void OnDraw(Canvas canvas) { base.OnDraw(canvas); canvas.Save(); canvas.Translate(_posX, _posY); canvas.Scale(_scaleFactor, _scaleFactor); _icon.Draw(canvas); canvas.Restore(); }
Ensuite, nous devons mettre à jour la variable
_scaleFactor
d’instance lorsque l’utilisateur pince leImageView
. Nous allons ajouter une classe appeléeMyScaleListener
. Cette classe écoute les événements de mise à l’échelle qui seront déclenchés par Android lorsque l’utilisateur pince leImageView
. Ajoutez la classe interne suivante àGestureRecognizerView
. Cette classe est unScaleGesture.SimpleOnScaleGestureListener
. Cette classe est une classe pratique que les écouteurs peuvent sous-classe lorsque vous êtes intéressé par un sous-ensemble de mouvements :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; } }
La méthode suivante dans laquelle nous devons remplacer
GestureRecognizerView
estOnTouchEvent
. Le code suivant répertorie l’implémentation complète de cette méthode. Il y a beaucoup de code ici, donc nous allons prendre une minute et regarder ce qui se passe ici. La première chose que cette méthode effectue est de mettre à l’échelle l’icône si nécessaire : elle est gérée en appelant_scaleDetector.OnTouchEvent
. Ensuite, nous essayons de déterminer l’action appelée cette méthode :Si l’utilisateur a touché l’écran, nous enregistrons les positions X et Y et l’ID du premier pointeur qui touchait l’écran.
Si l’utilisateur a déplacé son contact sur l’écran, nous allons déterminer jusqu’à quel point l’utilisateur a déplacé le pointeur.
Si l’utilisateur a levé son doigt sur l’écran, nous arrêterons de suivre les mouvements.
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; }
Exécutez maintenant l’application et démarrez l’activité Gesture Recognizer. Quand il démarre l’écran doit ressembler à la capture d’écran ci-dessous :
Appuyez maintenant sur l’icône et faites-la glisser autour de l’écran. Essayez le mouvement de pincement à zoom. À un moment donné, votre écran peut ressembler à la capture d’écran suivante :
À ce stade, vous devez vous donner une paton sur le dos : vous venez d’implémenter un pincement pour zoomer dans une application Android ! Prenez une pause rapide et passez à la troisième et dernière activité dans cette procédure pas à pas, à l’aide de mouvements personnalisés.
Activité de mouvement personnalisé
L’écran final de cette procédure pas à pas utilise des mouvements personnalisés.
Dans le cadre de cette procédure pas à pas, la bibliothèque de mouvements a déjà été créée à l’aide de l’outil Mouvement et ajoutée au projet dans les ressources de fichier /raw/gestures. Avec ce peu de ménage hors de la route, permet d’accéder à l’activité finale dans la procédure pas à pas.
Ajoutez un fichier de disposition nommé custom_gesture_layout.axml au projet avec le contenu suivant. Le projet comporte déjà toutes les images dans le dossier Ressources :
<?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>
Ajoutez ensuite une nouvelle activité au projet et nommez-la
CustomGestureRecognizerActivity.cs
. Ajoutez deux variables d’instance à la classe, comme indiqué dans les deux lignes de code suivantes :private GestureLibrary _gestureLibrary; private ImageView _imageView;
Modifiez la
OnCreate
méthode de cette activité afin qu’elle ressemble au code suivant. Prenons une minute pour expliquer ce qui se passe dans ce code. La première chose que nous faisons est d’instancier unGestureOverlayView
et de définir cela comme vue racine de l’activité. Nous affectons également un gestionnaire d’événements à l’événementGesturePerformed
deGestureOverlayView
. Ensuite, nous gonflons le fichier de disposition créé précédemment et ajoutez-le en tant qu’affichage enfant de l’objetGestureOverlayView
. La dernière étape consiste à initialiser la variable_gestureLibrary
et à charger le fichier de mouvements à partir des ressources de l’application. Si le fichier de mouvements ne peut pas être chargé pour une raison quelconque, il n’y a pas grand chose que cette activité peut faire, de sorte qu’elle est arrêtée :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(); } }
La dernière chose que nous devons effectuer pour implémenter la méthode
GestureOverlayViewOnGesturePerformed
, comme illustré dans l’extrait de code suivant. Lorsque leGestureOverlayView
message détecte un mouvement, il revient à cette méthode. La première chose que nous essayons d’obtenir unIList<Prediction>
objet qui correspond au mouvement en appelant_gestureLibrary.Recognize()
. Nous utilisons un peu linQ pour obtenir lePrediction
score le plus élevé pour le mouvement.S’il n’y a pas eu de mouvement correspondant avec un score suffisamment élevé, le gestionnaire d’événements quitte sans rien faire. Sinon, nous case activée le nom de la prédiction et modifier l’image affichée en fonction du nom du mouvement :
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); } }
Exécutez l’application et démarrez l’activité Custom Gesture Recognizer. Il doit ressembler à la capture d’écran suivante :
Dessinez maintenant une case activée mark sur l’écran, et l’image bitmap affichée doit ressembler à celle affichée dans les captures d’écran suivantes :
Enfin, dessinez un scribble sur l’écran. Le case activée box doit revenir à son image d’origine, comme illustré dans ces captures d’écran :
Vous avez maintenant une compréhension de l’intégration des interactions tactiles et des mouvements dans une application Android à l’aide de Xamarin.Android.