Пошаговое руководство. Использование сенсорного ввода в Android
Давайте посмотрим, как использовать основные понятия из предыдущего раздела в рабочем приложении. Мы создадим приложение с четырьмя действиями. Первое действие будет меню или коммутатор, которое запустит другие действия для демонстрации различных API. На следующем снимка экрана показана основная активность:
Первое действие, пример сенсорного ввода, показывает, как использовать обработчики событий для касания представлений. Действие распознавателя жестов демонстрирует, как подклассировать Android.View.Views
и обрабатывать события, а также как обрабатывать жесты сжатий. Третье и последнее действие, настраиваемый жест, показано, как использовать пользовательские жесты. Чтобы упростить следовать и поглощать, мы разорвем этот пошаговое руководство по разделам, с каждым разделом, ориентированным на одну из действий.
Пример действия касания
Откройте проект TouchWalkthrough_Start. MainActivity все настроено идти - это до нас, чтобы реализовать поведение касания в действии. При запуске приложения и нажатии кнопки Touch Sample необходимо запустить следующее действие:
Теперь, когда мы подтвердили, что действие запускается, откройте файл TouchActivity.cs и добавьте обработчик события
Touch
ImageView
:_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 на экране, как показано на следующем снимке экрана:
Если пользователь прикасается ImageView
к экрану, в элементе Touch Begins будет отображаться TextView
. Когда пользователь больше не касаетсяImageView
, в нем отобразится TextView
сообщение 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; } }
Следующий метод необходимо переопределить.
GestureRecognizerView
OnTouchEvent
В следующем коде перечислены полные реализации этого метода. Здесь есть много кода, поэтому позволяет занять минуту и посмотреть, что происходит здесь. Первое, что делает этот метод, — масштабирование значка при необходимости — это обрабатывается вызовом_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; }
Теперь запустите приложение и запустите действие распознавателя жестов. При запуске экрана должно выглядеть примерно так, как на снимок экрана ниже:
Теперь коснитесь значка и перетащите его по экрану. Попробуйте жест с закреплением к масштабу. В какой-то момент экран может выглядеть примерно так:
На этом этапе вы должны дать себе пальцем на спине: вы только что реализовали щип для масштабирования в приложении 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
и задать его в качестве корневого представления действия. Мы также назначаем обработчик событий событиюGesturePerformed
GestureOverlayView
. Затем мы раздуем созданный ранее файл макета и добавим его в качестве дочернего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); } }
Запустите приложение и запустите действие распознавателя пользовательских жестов. Он должен выглядеть примерно так, как на следующем снимок экрана:
Теперь нарисуйте знак проверка на экране, а отображаемое растровое изображение должно выглядеть примерно так, как показано на следующих снимках экрана:
Наконец, нарисуйте на экране скрибку. Поле проверка должно вернуться к исходному изображению, как показано на следующих снимках экрана:
Теперь вы узнаете, как интегрировать сенсорные и жесты в приложение Android с помощью Xamarin.Android.