Procedura dettagliata - Uso del tocco in Android

Vediamo come usare i concetti della sezione precedente in un'applicazione funzionante. Verrà creata un'applicazione con quattro attività. La prima attività sarà un menu o uno switchboard che avvierà le altre attività per illustrare le varie API. Lo screenshot seguente mostra l'attività principale:

Screenshot di esempio con il pulsante Touch Me

La prima attività, Touch Sample, mostrerà come usare i gestori eventi per toccare le visualizzazioni. L'attività Riconoscimento movimento illustra come sottoclassare Android.View.Views e gestire eventi, nonché come gestire i movimenti di avvicinamento delle dita. La terza e ultima attività, Custom Gesture, mostrerà come usare i movimenti personalizzati. Per semplificare il completamento e l'assorbimento, questa procedura dettagliata verrà suddivisa in sezioni, con ogni sezione incentrata su una delle attività.

Attività di esempio tocco

  • Aprire il TouchWalkthrough_Start del progetto. MainActivity è tutto pronto per andare– spetta a noi implementare il comportamento di tocco nell'attività. Se si esegue l'applicazione e si fa clic su Touch Sample, l'attività seguente dovrebbe essere avviata:

    Screenshot dell'attività con Touch Begins visualizzato

  • Ora che è stato confermato che l'attività viene avviata, aprire il file TouchActivity.cs e aggiungere un gestore per l'evento Touch di ImageView:

    _touchMeImageView.Touch += TouchMeImageViewOnTouch;
    
  • Aggiungere quindi il metodo seguente a 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;
    }
    

Si noti nel codice precedente che l'azione Move e Down viene considerata come la stessa. Ciò è dovuto al fatto che anche se l'utente potrebbe non sollevare il dito dall'oggetto ImageView, può muoversi o la pressione esercitata dall'utente può cambiare. Questi tipi di modifiche genereranno un'azione Move .

Ogni volta che l'utente tocca , ImageViewl'evento Touch verrà generato e il gestore visualizzerà il messaggio Touch Begins sullo schermo, come illustrato nello screenshot seguente:

Screenshot dell'attività con Touch Begins

Finché l'utente tocca , il ImageViewtocco inizia verrà visualizzato in TextView. Quando l'utente non tocca ImageViewpiù , il messaggio Touch Ends verrà visualizzato in TextView, come illustrato nello screenshot seguente:

Screenshot dell'attività con Touch Ends

Attività riconoscimento movimenti

Ora consente di implementare l'attività Riconoscimento movimento. Questa attività illustra come trascinare una visualizzazione sullo schermo e illustrare un modo per implementare il avvicinamento delle dita allo zoom.

  • Aggiungere una nuova attività all'applicazione denominata GestureRecognizer. Modificare il codice per questa attività in modo che sia simile al codice seguente:

    public class GestureRecognizerActivity : Activity
    {
        protected override void OnCreate(Bundle bundle)
        {
            base.OnCreate(bundle);
            View v = new GestureRecognizerView(this);
            SetContentView(v);
        }
    }
    
  • Aggiungere una nuova visualizzazione Android al progetto e denominarla GestureRecognizerView. Aggiungere le variabili seguenti a questa 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;
    
  • Aggiungere il costruttore seguente a GestureRecognizerView. Questo costruttore aggiungerà un oggetto all'attività ImageView . A questo punto il codice non verrà ancora compilato: è necessario creare la classe MyScaleListener che consentirà di ridimensionare ImageView quando l'utente lo avvicina:

    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));
    }
    
  • Per disegnare l'immagine sull'attività, è necessario eseguire l'override del OnDraw metodo della classe View, come illustrato nel frammento di codice seguente. Questo codice sposta l'oggetto ImageView nella posizione specificata da _posX e _posY ridimensiona l'immagine in base al fattore di ridimensionamento:

    protected override void OnDraw(Canvas canvas)
    {
        base.OnDraw(canvas);
        canvas.Save();
        canvas.Translate(_posX, _posY);
        canvas.Scale(_scaleFactor, _scaleFactor);
        _icon.Draw(canvas);
        canvas.Restore();
    }
    
  • Successivamente è necessario aggiornare la variabile _scaleFactor di istanza quando l'utente avvicina .ImageView Verrà aggiunta una classe denominata MyScaleListener. Questa classe sarà in ascolto degli eventi di scalabilità che verranno generati da Android quando l'utente avvicina .ImageView Aggiungere la classe interna seguente a GestureRecognizerView. Questa classe è un oggetto ScaleGesture.SimpleOnScaleGestureListener. Questa classe è una classe utile che i listener possono sottoclasse quando si è interessati a un subset di movimenti:

    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;
        }
    }
    
  • Il metodo successivo in cui è necessario eseguire l'override GestureRecognizerView è OnTouchEvent. Il codice seguente elenca l'implementazione completa di questo metodo. C'è un sacco di codice qui, quindi si può prendere un minuto e guardare cosa sta succedendo qui. La prima cosa che questo metodo esegue è ridimensionare l'icona, se necessario. Questa operazione viene gestita chiamando _scaleDetector.OnTouchEvent. Successivamente si tenta di capire quale azione ha chiamato questo metodo:

    • Se l'utente ha toccato lo schermo, registriamo le posizioni X e Y e l'ID del primo puntatore che ha toccato lo schermo.

    • Se l'utente ha spostato il tocco sullo schermo, si scoprirà quanto l'utente ha spostato il puntatore.

    • Se l'utente ha sollevato il dito dallo schermo, interromperemo il rilevamento dei movimenti.

    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;
    }
    
  • Eseguire ora l'applicazione e avviare l'attività Riconoscimento movimento. All'avvio della schermata dovrebbe essere simile allo screenshot seguente:

    Schermata start di Riconoscimento movimenti con l'icona Android

  • Toccare ora l'icona e trascinarla sullo schermo. Provare il movimento di avvicinamento delle dita allo zoom. A un certo punto la schermata potrebbe essere simile alla schermata seguente:

    I movimenti spostano l'icona intorno allo schermo

A questo punto dovresti darti una pat sulla schiena: hai appena implementato il avvicinamento delle dita per ingrandire un'applicazione Android! Fare una pausa rapida e consente di passare alla terza e ultima attività in questa procedura dettagliata, usando movimenti personalizzati.

Attività movimento personalizzata

La schermata finale di questa procedura dettagliata userà movimenti personalizzati.

Ai fini di questa procedura dettagliata, la libreria di movimenti è già stata creata usando lo strumento movimento e aggiunta al progetto nel file Resources/raw/gestures. Con questo po ' di pulizia fuori dal modo, consente di iniziare con l'attività finale nella procedura dettagliata.

  • Aggiungere un file di layout denominato custom_gesture_layout.axml al progetto con il contenuto seguente. Il progetto include già tutte le immagini nella cartella Risorse :

    <?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>
    
  • Aggiungere quindi una nuova attività al progetto e denominarla CustomGestureRecognizerActivity.cs. Aggiungere due variabili di istanza alla classe , come illustrato nelle due righe di codice seguenti:

    private GestureLibrary _gestureLibrary;
    private ImageView _imageView;
    
  • Modificare il OnCreate metodo dell'attività in modo che sia simile al codice seguente. Consente di dedicare qualche minuto a spiegare cosa sta succedendo in questo codice. La prima cosa che facciamo è creare un'istanza GestureOverlayView di e impostarne una come visualizzazione radice dell'attività. Viene inoltre assegnato un gestore eventi all'evento GesturePerformed di GestureOverlayView. Successivamente, si gonfia il file di layout creato in precedenza e lo si aggiunge come visualizzazione figlio dell'oggetto GestureOverlayView. Il passaggio finale consiste nell'inizializzare la variabile _gestureLibrary e caricare il file dei movimenti dalle risorse dell'applicazione. Se il file di movimenti non può essere caricato per qualche motivo, non è possibile eseguire molte operazioni di questo tipo di attività, in modo da arrestare:

    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();
        }
    }
    
  • L'ultima operazione da eseguire per implementare il metodo GestureOverlayViewOnGesturePerformed , come illustrato nel frammento di codice seguente. GestureOverlayView Quando rileva un movimento, viene chiamato a questo metodo. La prima cosa che si tenta di ottenere un IList<Prediction> oggetto che corrisponde al movimento chiamando _gestureLibrary.Recognize(). Per ottenere il Prediction punteggio più alto per il movimento viene usato un po' di LINQ.

    Se non è presente alcun movimento corrispondente con un punteggio sufficientemente alto, il gestore eventi viene chiuso senza eseguire alcuna operazione. In caso contrario, controlliamo il nome della stima e modifichiamo l'immagine visualizzata in base al nome del movimento:

    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);
        }
    }
    
  • Eseguire l'applicazione e avviare l'attività Riconoscimento movimento personalizzato. Dovrebbe essere simile allo screenshot seguente:

    Screenshot con l'immagine Check Me

    Disegnare ora un segno di spunta sullo schermo e la bitmap visualizzata dovrebbe essere simile a quella mostrata negli screenshot successivi:

    Segno di spunta disegnato, segno di spunta riconosciuto

    Infine, disegnare una scarabocchia sullo schermo. La casella di controllo deve tornare all'immagine originale, come illustrato negli screenshot seguenti:

    Scribble sullo schermo, viene visualizzata l'immagine originale

Si ha ora una conoscenza di come integrare il tocco e i movimenti in un'applicazione Android usando Xamarin.Android.