Пошаговое руководство. Использование сенсорного ввода в Android

Давайте посмотрим, как использовать основные понятия из предыдущего раздела в рабочем приложении. Мы создадим приложение с четырьмя действиями. Первое действие будет меню или коммутатор, которое запустит другие действия для демонстрации различных API. На следующем снимка экрана показана основная активность:

Example screenshot with Touch Me button

Первое действие, пример сенсорного ввода, показывает, как использовать обработчики событий для касания представлений. Действие распознавателя жестов демонстрирует, как подклассировать Android.View.Views и обрабатывать события, а также как обрабатывать жесты сжатий. Третье и последнее действие, настраиваемый жест, показано, как использовать пользовательские жесты. Чтобы упростить следовать и поглощать, мы разорвем этот пошаговое руководство по разделам, с каждым разделом, ориентированным на одну из действий.

Пример действия касания

  • Откройте проект TouchWalkthrough_Start. MainActivity все настроено идти - это до нас, чтобы реализовать поведение касания в действии. При запуске приложения и нажатии кнопки Touch Sample необходимо запустить следующее действие:

    Screenshot of activity with Touch Begins displayed

  • Теперь, когда мы подтвердили, что действие запускается, откройте файл TouchActivity.cs и добавьте обработчик события TouchImageView:

    _touchMeImageView.Touch += TouchMeImageViewOnTouch;
    
  • Затем добавьте следующий метод для 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;
    }
    

Обратите внимание, что в приведенном выше коде мы рассмотрим Move и Down действие как то же самое. Это связано с тем, что, несмотря на то, что пользователь не может поднять пальцем от ImageViewнего, он может перемещаться или давление, которое оказывает пользователь, может измениться. Эти типы изменений создают Move действие.

Каждый раз, когда пользователь прикасается ImageViewк событию, Touch событие будет возникать, и наш обработчик отобразит сообщение Touch Begins на экране, как показано на следующем снимке экрана:

Screenshot of activity with Touch Begins

Если пользователь прикасается ImageViewк экрану, в элементе Touch Begins будет отображаться TextView. Когда пользователь больше не касаетсяImageView, в нем отобразится TextViewсообщение Touch Ends , как показано на следующем снимке экрана:

Screenshot of activity with Touch Ends

Действие распознавателя жестов

Теперь позволяет реализовать действие распознавателя жестов. В этом действии показано, как перетащить представление по экрану и проиллюстрировать один из способов реализации масштабирования.

  • Добавьте новое действие в вызываемое GestureRecognizerприложение. Измените код для этого действия, чтобы он выглядел следующим образом:

    public class GestureRecognizerActivity : Activity
    {
        protected override void OnCreate(Bundle bundle)
        {
            base.OnCreate(bundle);
            View v = new GestureRecognizerView(this);
            SetContentView(v);
        }
    }
    
  • Добавьте новое представление Android в проект и назовите его GestureRecognizerView. Добавьте следующие переменные в этот класс:

    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;
    
  • Добавьте следующий конструктор GestureRecognizerViewв . Этот конструктор добавит ImageView в действие. На этом этапе код по-прежнему не будет компилироваться. Необходимо создать класс MyScaleListener , который поможет изменить ImageView размер, когда пользователь нажимает на него:

    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));
    }
    
  • Чтобы нарисовать изображение на нашем действии, необходимо переопределить OnDraw метод класса View, как показано в следующем фрагменте кода. Этот код перемещает ImageView положение, указанное _posX и _posY изменяя размер изображения в соответствии с коэффициентом масштабирования:

    protected override void OnDraw(Canvas canvas)
    {
        base.OnDraw(canvas);
        canvas.Save();
        canvas.Translate(_posX, _posY);
        canvas.Scale(_scaleFactor, _scaleFactor);
        _icon.Draw(canvas);
        canvas.Restore();
    }
    
  • Затем необходимо обновить переменную _scaleFactor экземпляра по мере того, как пользователь нажимает на нее ImageView. Мы добавим класс с именем MyScaleListener. Этот класс будет прослушивать события масштабирования, которые будут вызываться Android, когда пользователь нажимает.ImageView Добавьте следующий внутренний класс GestureRecognizerViewв . Этот класс является ScaleGesture.SimpleOnScaleGestureListener. Этот класс — это удобный класс, который прослушиватели могут подклассовать при наличии подмножества жестов:

    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;
        }
    }
    
  • Следующий метод необходимо переопределить.GestureRecognizerViewOnTouchEvent В следующем коде перечислены полные реализации этого метода. Здесь есть много кода, поэтому позволяет занять минуту и посмотреть, что происходит здесь. Первое, что делает этот метод, — масштабирование значка при необходимости — это обрабатывается вызовом _scaleDetector.OnTouchEvent. Далее мы пытаемся выяснить, какое действие называется этим методом:

    • Если пользователь коснулся экрана, мы записываем позиции X и Y и идентификатор первого указателя, касающегося экрана.

    • Если пользователь переместил свой сенсорный ввод на экране, мы посмотрим, насколько далеко пользователь переместил указатель.

    • Если пользователь поднял пальцем с экрана, мы перестаем отслеживать жесты.

    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;
    }
    
  • Теперь запустите приложение и запустите действие распознавателя жестов. При запуске экрана должно выглядеть примерно так, как на снимок экрана ниже:

    Gesture Recognizer start screen with Android icon

  • Теперь коснитесь значка и перетащите его по экрану. Попробуйте жест с закреплением к масштабу. В какой-то момент экран может выглядеть примерно так:

    Gestures move icon around the screen

На этом этапе вы должны дать себе пальцем на спине: вы только что реализовали щип для масштабирования в приложении Android! Выполните быстрый перерыв и позволяет перейти к третьему и последнему действиям в этом пошаговом руководстве с помощью пользовательских жестов.

Действие пользовательского жеста

Последний экран в этом пошаговом руководстве будет использовать пользовательские жесты.

В этом пошаговом руководстве библиотека жестов уже создана с помощью средства жестов и добавлена в проект в файле Resources/raw/gestures. С этим битом домашней уборки вне пути, позволяет получить с окончательным действием в пошаговом руководстве.

  • Добавьте файл макета с именем custom_gesture_layout.axml в проект со следующим содержимым. Проект уже содержит все изображения в папке Resources :

    <?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>
    
  • Затем добавьте новое действие в проект и назовите его CustomGestureRecognizerActivity.cs. Добавьте две переменные экземпляра в класс, как показано в следующих двух строках кода:

    private GestureLibrary _gestureLibrary;
    private ImageView _imageView;
    
  • Измените OnCreate метод этого действия таким образом, чтобы он напоминал следующий код. Давайте минуту объясним, что происходит в этом коде. Первое, что мы делаем, — создать экземпляр GestureOverlayView и задать его в качестве корневого представления действия. Мы также назначаем обработчик событий событию GesturePerformedGestureOverlayView. Затем мы раздуем созданный ранее файл макета и добавим его в качестве дочернего GestureOverlayViewпредставления. Последним шагом является инициализация переменной _gestureLibrary и загрузка файла жестов из ресурсов приложения. Если файл жестов не может быть загружен по какой-то причине, это действие может сделать не так много, поэтому это завершение работы:

    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();
        }
    }
    
  • Последнее, что нам нужно сделать, чтобы реализовать метод GestureOverlayViewOnGesturePerformed , как показано в следующем фрагменте кода. GestureOverlayView При обнаружении жеста он возвращается к этому методу. Первое, что мы пытаемся получить IList<Prediction> объекты, соответствующие жесту, вызывая _gestureLibrary.Recognize(). Мы используем немного LINQ, чтобы получить Prediction самую высокую оценку для жеста.

    Если не было соответствующего жеста с достаточно высоким показателем, обработчик событий завершает работу без каких-либо действий. В противном случае мы проверка имя прогноза и измените отображаемое изображение на основе имени жеста:

    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);
        }
    }
    
  • Запустите приложение и запустите действие распознавателя пользовательских жестов. Он должен выглядеть примерно так, как на следующем снимок экрана:

    Screenshot with Check Me image

    Теперь нарисуйте знак проверка на экране, а отображаемое растровое изображение должно выглядеть примерно так, как показано на следующих снимках экрана:

    Drawn checkmark, checkmark is recognized

    Наконец, нарисуйте на экране скрибку. Поле проверка должно вернуться к исходному изображению, как показано на следующих снимках экрана:

    Scribble on the screen, original image is displayed

Теперь вы узнаете, как интегрировать сенсорные и жесты в приложение Android с помощью Xamarin.Android.