Compartilhar via


Demonstra Passo a passo: Usando o toque no Xamarin.iOS

Este passo a passo demonstra como escrever código que responde a diferentes tipos de eventos de toque. Cada exemplo está contido em uma tela separada:

  • Amostras de toque – como responder a eventos de toque.
  • Exemplos do Gesture Recognizer – como usar reconhecedores de gestos integrados.
  • Exemplo de reconhecedor de gesto personalizado – como criar um reconhecedor de gesto personalizado.

Cada seção contém instruções para escrever o código do zero.

Siga as instruções abaixo para adicionar código ao storyboard e saiba mais sobre os diferentes tipos de eventos de toque disponíveis no iOS.

Amostras de toque

Neste exemplo, demonstraremos algumas das APIs de toque. Siga estas etapas para adicionar o código necessário para implementar eventos de toque:

  1. Abra o Touch_Start do projeto. Primeiro, execute o projeto para garantir que tudo esteja bem e toque no botão Touch Samples . Você verá uma tela semelhante à seguinte (embora nenhum dos botões funcione):

    Aplicativo de exemplo executado com botões que não funcionam

  2. Edite o TouchViewController.cs de arquivo e adicione as duas variáveis de instância a seguir à classeTouchViewController:

    #region Private Variables
    private bool imageHighlighted = false;
    private bool touchStartedInside;
    #endregion
    
  3. Implemente o TouchesBegan método, conforme mostrado no código abaixo:

    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;
            }
        }
    }
    

    Esse método funciona verificando um UITouch objeto e, se ele existir, execute alguma ação com base em onde o toque ocorreu:

    • Dentro de TouchImage – exibe o texto Touches Began em um rótulo e altera a imagem.
    • Dentro de DoubleTouchImage – altere a imagem exibida se o gesto foi um toque duplo.
    • Dentro de DragImage – defina um sinalizador indicando que o toque foi iniciado. O método TouchesMoved usará esse sinalizador para determinar se DragImage deve ser movido pela tela ou não, como veremos na próxima etapa.

    O código acima trata apenas de toques individuais, ainda não há comportamento se o usuário estiver movendo o dedo na tela. Para responder ao movimento, implemente TouchesMoved como mostrado no código abaixo:

    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);
            }
        }
    }
    

    Esse método obtém um UITouch objeto e, em seguida, verifica onde o toque ocorreu. Se o toque ocorreu no TouchImage, o texto Toques Movidos será exibido na tela.

    Se touchStartedInside for verdade, então sabemos que o usuário está com o dedo e DragImage está movendo-o. O código se moverá DragImage à medida que o usuário mover o dedo pela tela.

  4. Precisamos lidar com o caso quando o usuário tira o dedo da tela ou o iOS cancela o evento de toque. Para isso, vamos implementar TouchesEnded e TouchesCancelled conforme mostrado abaixo:

    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;
    }
    

    Ambos os métodos redefinirão o touchStartedInside sinalizador para false. TouchesEnded também será exibido TouchesEnded na tela.

  5. Neste ponto, a tela Touch Samples está concluída. Observe como a tela muda à medida que você interage com cada uma das imagens, conforme mostrado na captura de tela a seguir:

    A tela inicial do aplicativo

    A tela após o usuário arrastar um botão

Exemplos do Reconhecedor de Gestos

A seção anterior demonstrou como arrastar um objeto pela tela usando eventos de toque. Nesta seção, vamos nos livrar dos eventos de toque e mostrar como usar os seguintes reconhecedores de gestos:

  • O UIPanGestureRecognizer para arrastar uma imagem pela tela.
  • O UITapGestureRecognizer para responder a toques duplos na tela.

Siga estas etapas para implementar reconhecedores de gestos:

  1. Edite o GestureViewController.cs de arquivo e adicione a seguinte variável de instância:

    #region Private Variables
    private bool imageHighlighted = false;
    private RectangleF originalImageFrame = RectangleF.Empty;
    #endregion
    

    Precisamos dessa variável de instância para acompanhar o local anterior da imagem. O reconhecedor de gestos de panorâmica usará o originalImageFrame valor para calcular o deslocamento necessário para redesenhar a imagem na tela.

  2. Adicione o seguinte método ao controlador:

    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);
    }
    

    Esse código instancia uma UIPanGestureRecognizer instância e a adiciona a uma exibição. Observe que atribuímos um destino ao gesto na forma do método HandleDrag – esse método é fornecido na próxima etapa.

  3. Para implementar HandleDrag, adicione o seguinte código ao controlador:

    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;
        }
    }
    

    O código acima verificará primeiro o estado do reconhecedor de gestos e, em seguida, moverá a imagem pela tela. Com esse código no lugar, o controlador agora pode suportar arrastar uma imagem ao redor da tela.

  4. Adicione um UITapGestureRecognizer que alterará a imagem que está sendo exibida em DoubleTouchImage. Adicione o seguinte método ao GestureViewController controlador:

    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);
    }
    

    Esse código é muito semelhante ao código para o UIPanGestureRecognizer mas em vez de usar um delegado para um destino, estamos usando um Actionarquivo .

  5. A última coisa que precisamos fazer é modificar ViewDidLoad para que ele chame os métodos que acabamos de adicionar. Altere ViewDidLoad para que se assemelhe ao seguinte código:

    public override void ViewDidLoad()
    {
        base.ViewDidLoad();
    
        Title = "Gesture Recognizers";
    
        // Save initial state
        originalImageFrame = DragImage.Frame;
    
        WireUpTapGestureRecognizer();
        WireUpDragGestureRecognizer();
    }
    

    Observe também que inicializamos o valor de originalImageFrame.

  6. Execute o aplicativo e interaja com as duas imagens. A captura de tela a seguir é um exemplo dessas interações:

    Esta captura de tela mostra uma interação de arrastar

Reconhecedor de gestos personalizados

Nesta seção, aplicaremos os conceitos das seções anteriores para criar um reconhecedor de gestos personalizado. O reconhecedor de gestos personalizados subclasses UIGestureRecognizere reconhecerá quando o usuário desenhar um "V" na tela e, em seguida, alternar um bitmap. A captura de tela a seguir é um exemplo dessa tela:

O aplicativo reconhecerá quando o usuário desenhar um V na tela

Siga estas etapas para criar um reconhecedor de gestos personalizado:

  1. Adicione uma nova classe ao projeto chamado CheckmarkGestureRecognizer, e faça com que ele se pareça com o seguinte código:

    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
        }
    }
    

    O método Reset é chamado quando a State propriedade é alterada para Recognized ou Ended. Este é o momento de redefinir qualquer estado interno definido no reconhecedor de gestos personalizado. Agora, a classe pode começar de novo na próxima vez que o usuário interagir com o aplicativo e estar pronto para tentar novamente reconhecer o gesto.

  2. Agora que definimos um reconhecedor de gestos personalizado (CheckmarkGestureRecognizer) edite o arquivo CustomGestureViewController.cs e adicione as duas variáveis de instância a seguir:

    #region Private Variables
    private bool isChecked = false;
    private CheckmarkGestureRecognizer checkmarkGesture;
    #endregion
    
  3. Para instanciar e configurar nosso reconhecedor de gestos, adicione o seguinte método ao controlador:

    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);
    }
    
  4. Edite ViewDidLoad para que ele chame WireUpCheckmarkGestureRecognizer, conforme mostrado no seguinte trecho de código:

    public override void ViewDidLoad()
    {
        base.ViewDidLoad();
    
        // Wire up the gesture recognizer
        WireUpCheckmarkGestureRecognizer();
    }
    
  5. Execute o aplicativo e tente desenhar um "V" na tela. Você deve ver a imagem que está sendo exibida mudar, como mostrado nas seguintes capturas de tela:

    O botão verificado

    O botão desmarcado

As três seções acima demonstraram diferentes maneiras de responder a eventos de toque no iOS: usando eventos de toque, reconhecedores de gestos integrados ou com um reconhecedor de gestos personalizado.