Пошаговое руководство. Использование сенсорного ввода в Xamarin.iOS
В этом пошаговом руководстве показано, как писать код, реагирующий на различные виды событий касания. Каждый пример содержится на отдельном экране:
- Примеры касания — как реагировать на события касания.
- Примеры распознавателя жестов — как использовать встроенные распознаватели жестов.
- Пример распознавателя пользовательских жестов — создание пользовательского распознавателя жестов.
Каждый раздел содержит инструкции по написанию кода с нуля.
Следуйте приведенным ниже инструкциям, чтобы добавить код в раскадровку и узнать о различных типах событий касания, доступных в iOS.
Примеры касания
В этом примере мы продемонстрируем некоторые интерфейсы API сенсорного ввода. Выполните следующие действия, чтобы добавить код, необходимый для реализации событий сенсорного ввода:
Откройте проект Touch_Start. Сначала запустите проект, чтобы убедиться, что все хорошо, и нажмите кнопку "Примеры касания". Вы должны увидеть экран, аналогичный следующему (хотя ни одна из кнопок не будет работать):
Измените файл TouchViewController.cs и добавьте в класс
TouchViewController
следующие две переменные экземпляра:#region Private Variables private bool imageHighlighted = false; private bool touchStartedInside; #endregion
TouchesBegan
Реализуйте метод, как показано в приведенном ниже коде:public override void TouchesBegan(NSSet touches, UIEvent evt) { base.TouchesBegan(touches, evt); // If Multitouch is enabled, report the number of fingers down TouchStatus.Text = string.Format ("Number of fingers {0}", touches.Count); // Get the current touch UITouch touch = touches.AnyObject as UITouch; if (touch != null) { // Check to see if any of the images have been touched if (TouchImage.Frame.Contains(touch.LocationInView(TouchView))) { // Fist image touched TouchImage.Image = UIImage.FromBundle("TouchMe_Touched.png"); TouchStatus.Text = "Touches Began"; } else if (touch.TapCount == 2 && DoubleTouchImage.Frame.Contains(touch.LocationInView(TouchView))) { // Second image double-tapped, toggle bitmap if (imageHighlighted) { DoubleTouchImage.Image = UIImage.FromBundle("DoubleTapMe.png"); TouchStatus.Text = "Double-Tapped Off"; } else { DoubleTouchImage.Image = UIImage.FromBundle("DoubleTapMe_Highlighted.png"); TouchStatus.Text = "Double-Tapped On"; } imageHighlighted = !imageHighlighted; } else if (DragImage.Frame.Contains(touch.LocationInView(View))) { // Third image touched, prepare to drag touchStartedInside = true; } } }
Этот метод работает путем проверка для
UITouch
объекта, и если он существует, выполните некоторые действия в зависимости от того, где произошло касание:- Внутри TouchImage — отображение текста
Touches Began
в метке и изменение изображения. - Внутри DoubleTouchImage — измените изображение, отображаемое, если жест был двойным касанием.
- Внутри DragImage — задайте флаг, указывающий, что сенсорный элемент запущен. Метод
TouchesMoved
будет использовать этот флаг, чтобы определить, следует лиDragImage
перемещаться по экрану или нет, как показано на следующем шаге.
Приведенный выше код имеет дело только с отдельными касаниями, по-прежнему нет поведения, если пользователь перемещает пальцем на экране. Чтобы реагировать на перемещение, реализуйте
TouchesMoved
, как показано в приведенном ниже коде:public override void TouchesMoved(NSSet touches, UIEvent evt) { base.TouchesMoved(touches, evt); // get the touch UITouch touch = touches.AnyObject as UITouch; if (touch != null) { //==== IMAGE TOUCH if (TouchImage.Frame.Contains(touch.LocationInView(TouchView))) { TouchStatus.Text = "Touches Moved"; } //==== IMAGE DRAG // check to see if the touch started in the drag me image if (touchStartedInside) { // move the shape float offsetX = touch.PreviousLocationInView(View).X - touch.LocationInView(View).X; float offsetY = touch.PreviousLocationInView(View).Y - touch.LocationInView(View).Y; DragImage.Frame = new RectangleF(new PointF(DragImage.Frame.X - offsetX, DragImage.Frame.Y - offsetY), DragImage.Frame.Size); } } }
Этот метод получает
UITouch
объект, а затем проверка, чтобы узнать, где произошло касание. Если касание произошло вTouchImage
, на экране отображается текст с перемещением сенсорного ввода.Если
touchStartedInside
это верно, то мы знаем, что пользователь имеет палецDragImage
и перемещает его вокруг. Код будет перемещатьсяDragImage
, когда пользователь перемещает пальцем по экрану.- Внутри TouchImage — отображение текста
Нам нужно справиться с ситуацией, когда пользователь поднимает пальцем с экрана, или iOS отменяет событие сенсорного ввода. Для этого мы реализуем
TouchesEnded
иTouchesCancelled
как показано ниже:public override void TouchesCancelled(NSSet touches, UIEvent evt) { base.TouchesCancelled(touches, evt); // reset our tracking flags touchStartedInside = false; TouchImage.Image = UIImage.FromBundle("TouchMe.png"); TouchStatus.Text = ""; } public override void TouchesEnded(NSSet touches, UIEvent evt) { base.TouchesEnded(touches, evt); // get the touch UITouch touch = touches.AnyObject as UITouch; if (touch != null) { //==== IMAGE TOUCH if (TouchImage.Frame.Contains(touch.LocationInView(TouchView))) { TouchImage.Image = UIImage.FromBundle("TouchMe.png"); TouchStatus.Text = "Touches Ended"; } } // reset our tracking flags touchStartedInside = false; }
Оба этих метода сбрасывают
touchStartedInside
флаг на false.TouchesEnded
также отобразитсяTouchesEnded
на экране.На этом этапе будет завершен экран "Примеры сенсорного ввода". Обратите внимание, как экран изменяется при взаимодействии с каждым из изображений, как показано на следующем снимке экрана:
Примеры распознавателя жестов
В предыдущем разделе показано, как перетащить объект по экрану с помощью событий сенсорного ввода. В этом разделе мы избавимся от событий касания и покажем, как использовать следующие распознаватели жестов:
- Для
UIPanGestureRecognizer
перетаскивания изображения на экране. - Ответ
UITapGestureRecognizer
на двойные касания экрана.
Выполните следующие действия, чтобы реализовать распознаватели жестов:
Измените файл GestureViewController.cs и добавьте следующую переменную экземпляра:
#region Private Variables private bool imageHighlighted = false; private RectangleF originalImageFrame = RectangleF.Empty; #endregion
Нам нужна эта переменная экземпляра для отслеживания предыдущего расположения образа. Распознаватель жестов сдвига будет использовать
originalImageFrame
значение для вычисления смещения, необходимого для перерасчета изображения на экране.Добавьте в контроллер следующий метод:
private void WireUpDragGestureRecognizer() { // Create a new tap gesture UIPanGestureRecognizer gesture = new UIPanGestureRecognizer(); // Wire up the event handler (have to use a selector) gesture.AddTarget(() => HandleDrag(gesture)); // to be defined // Add the gesture recognizer to the view DragImage.AddGestureRecognizer(gesture); }
Этот код создает экземпляр
UIPanGestureRecognizer
и добавляет его в представление. Обратите внимание, что мы назначаем целевой объект жесту в виде методаHandleDrag
. Этот метод предоставляется на следующем шаге.Чтобы реализовать HandleDrag, добавьте следующий код в контроллер:
private void HandleDrag(UIPanGestureRecognizer recognizer) { // If it's just began, cache the location of the image if (recognizer.State == UIGestureRecognizerState.Began) { originalImageFrame = DragImage.Frame; } // Move the image if the gesture is valid if (recognizer.State != (UIGestureRecognizerState.Cancelled | UIGestureRecognizerState.Failed | UIGestureRecognizerState.Possible)) { // Move the image by adding the offset to the object's frame PointF offset = recognizer.TranslationInView(DragImage); RectangleF newFrame = originalImageFrame; newFrame.Offset(offset.X, offset.Y); DragImage.Frame = newFrame; } }
Приведенный выше код сначала проверка состояние распознавателя жестов, а затем переместить изображение по экрану. В этом коде контроллер теперь может поддерживать перетаскивание одного изображения на экране.
Добавьте объект
UITapGestureRecognizer
, который изменит изображение, отображаемое в DoubleTouchImage. Добавьте в контроллер следующий методGestureViewController
:private void WireUpTapGestureRecognizer() { // Create a new tap gesture UITapGestureRecognizer tapGesture = null; // Report touch Action action = () => { TouchStatus.Text = string.Format("Image touched at: {0}",tapGesture.LocationOfTouch(0, DoubleTouchImage)); // Toggle the image if (imageHighlighted) { DoubleTouchImage.Image = UIImage.FromBundle("DoubleTapMe.png"); } else { DoubleTouchImage.Image = UIImage.FromBundle("DoubleTapMe_Highlighted.png"); } imageHighlighted = !imageHighlighted; }; tapGesture = new UITapGestureRecognizer(action); // Configure it tapGesture.NumberOfTapsRequired = 2; // Add the gesture recognizer to the view DoubleTouchImage.AddGestureRecognizer(tapGesture); }
Этот код очень похож на код для
UIPanGestureRecognizer
кода, но вместо использования делегата для целевого объекта, который мы используемAction
.Последнее, что необходимо сделать, заключается в изменении
ViewDidLoad
, чтобы он вызывает только что добавленные методы. Измените ViewDidLoad, чтобы он выглядел следующим образом:public override void ViewDidLoad() { base.ViewDidLoad(); Title = "Gesture Recognizers"; // Save initial state originalImageFrame = DragImage.Frame; WireUpTapGestureRecognizer(); WireUpDragGestureRecognizer(); }
Обратите внимание, что мы инициализируем значение
originalImageFrame
.Запустите приложение и взаимодействуйте с двумя изображениями. На следующем снимках экрана показан один из примеров этих взаимодействий:
Распознаватель пользовательских жестов
В этом разделе мы будем применять основные понятия из предыдущих разделов для создания пользовательского распознавателя жестов. Распознаватель пользовательских жестов будет подклассами UIGestureRecognizer
и распознает, когда пользователь рисует "V" на экране, а затем переключает растровое изображение. На следующем снимок экрана показан пример этого экрана:
Выполните следующие действия, чтобы создать распознаватель пользовательских жестов:
Добавьте новый класс в проект с именем
CheckmarkGestureRecognizer
и сделайте его следующим кодом:using System; using CoreGraphics; using Foundation; using UIKit; namespace Touch { public class CheckmarkGestureRecognizer : UIGestureRecognizer { #region Private Variables private CGPoint midpoint = CGPoint.Empty; private bool strokeUp = false; #endregion #region Override Methods /// <summary> /// Called when the touches end or the recognizer state fails /// </summary> public override void Reset() { base.Reset(); strokeUp = false; midpoint = CGPoint.Empty; } /// <summary> /// Is called when the fingers touch the screen. /// </summary> public override void TouchesBegan(NSSet touches, UIEvent evt) { base.TouchesBegan(touches, evt); // we want one and only one finger if (touches.Count != 1) { base.State = UIGestureRecognizerState.Failed; } Console.WriteLine(base.State.ToString()); } /// <summary> /// Called when the touches are cancelled due to a phone call, etc. /// </summary> public override void TouchesCancelled(NSSet touches, UIEvent evt) { base.TouchesCancelled(touches, evt); // we fail the recognizer so that there isn't unexpected behavior // if the application comes back into view base.State = UIGestureRecognizerState.Failed; } /// <summary> /// Called when the fingers lift off the screen /// </summary> public override void TouchesEnded(NSSet touches, UIEvent evt) { base.TouchesEnded(touches, evt); // if (base.State == UIGestureRecognizerState.Possible && strokeUp) { base.State = UIGestureRecognizerState.Recognized; } Console.WriteLine(base.State.ToString()); } /// <summary> /// Called when the fingers move /// </summary> public override void TouchesMoved(NSSet touches, UIEvent evt) { base.TouchesMoved(touches, evt); // if we haven't already failed if (base.State != UIGestureRecognizerState.Failed) { // get the current and previous touch point CGPoint newPoint = (touches.AnyObject as UITouch).LocationInView(View); CGPoint previousPoint = (touches.AnyObject as UITouch).PreviousLocationInView(View); // if we're not already on the upstroke if (!strokeUp) { // if we're moving down, just continue to set the midpoint at // whatever point we're at. when we start to stroke up, it'll stick // as the last point before we upticked if (newPoint.X >= previousPoint.X && newPoint.Y >= previousPoint.Y) { midpoint = newPoint; } // if we're stroking up (moving right x and up y [y axis is flipped]) else if (newPoint.X >= previousPoint.X && newPoint.Y <= previousPoint.Y) { strokeUp = true; } // otherwise, we fail the recognizer else { base.State = UIGestureRecognizerState.Failed; } } } Console.WriteLine(base.State.ToString()); } #endregion } }
Метод Reset вызывается, когда
State
свойство изменяется на одноRecognized
или.Ended
Это время для сброса любого внутреннего состояния, заданного в пользовательском распознавателье жестов. Теперь класс может начать новый при следующем взаимодействии пользователя с приложением и быть готовым к повторной попытке распознавания жеста.Теперь, когда мы определили настраиваемый распознаватель жестов (
CheckmarkGestureRecognizer
) измените файл CustomGestureViewController.cs и добавьте следующие две переменные экземпляра:#region Private Variables private bool isChecked = false; private CheckmarkGestureRecognizer checkmarkGesture; #endregion
Чтобы создать экземпляр и настроить распознаватель жестов, добавьте следующий метод в контроллер:
private void WireUpCheckmarkGestureRecognizer() { // Create the recognizer checkmarkGesture = new CheckmarkGestureRecognizer(); // Wire up the event handler checkmarkGesture.AddTarget(() => { if (checkmarkGesture.State == (UIGestureRecognizerState.Recognized | UIGestureRecognizerState.Ended)) { if (isChecked) { CheckboxImage.Image = UIImage.FromBundle("CheckBox_Unchecked.png"); } else { CheckboxImage.Image = UIImage.FromBundle("CheckBox_Checked.png"); } isChecked = !isChecked; } }); // Add the gesture recognizer to the view View.AddGestureRecognizer(checkmarkGesture); }
Измените
ViewDidLoad
его так, чтобы он вызываетсяWireUpCheckmarkGestureRecognizer
, как показано в следующем фрагменте кода:public override void ViewDidLoad() { base.ViewDidLoad(); // Wire up the gesture recognizer WireUpCheckmarkGestureRecognizer(); }
Запустите приложение и попробуйте нарисовать "V" на экране. Вы должны увидеть отображаемое изображение, как показано на следующих снимках экрана:
Приведенные выше три раздела демонстрируют различные способы реагирования на события касания в iOS: использование событий сенсорного ввода, встроенных распознавателей жестов или пользовательского распознавателя жестов.