Eventos e gestos de toque no Xamarin.iOS

É importante entender os eventos de toque e as APIs de toque em um aplicativo iOS, pois eles são centrais para todas as interações físicas com o dispositivo. Todas as interações por toque envolvem um UITouch objeto . Neste artigo, aprenderemos a usar a UITouch classe e suas APIs para dar suporte ao toque. Posteriormente, expandiremos nosso conhecimento para aprender a dar suporte a gestos.

Habilitando o Toque

Os controles em UIKit – aqueles subclasses de UIControl – são tão dependentes da interação do usuário que têm gestos integrados ao UIKit e, portanto, não é necessário habilitar o Touch. Ele já está habilitado.

No entanto, muitos dos modos de exibição no UIKit não têm toque habilitado por padrão. Há duas maneiras de habilitar o toque em um controle. A primeira maneira é marcar caixa de seleção Interação do Usuário Habilitada no Painel de Propriedades do Designer do iOS, conforme mostrado na captura de tela a seguir:

Marque a caixa de seleção Interação do Usuário Habilitada no Painel de Propriedades do Designer do iOS

Também podemos usar um controlador para definir a UserInteractionEnabled propriedade como true em uma UIView classe. Isso será necessário se a interface do usuário for criada no código.

A seguinte linha de código é um exemplo:

imgTouchMe.UserInteractionEnabled = true;

Eventos de Toque

Há três fases de toque que ocorrem quando o usuário toca na tela, move o dedo ou remove o dedo. Esses métodos são definidos em UIResponder, que é a classe base para UIView. O iOS substituirá os métodos associados no UIView e no para manipular o UIViewController toque:

  • TouchesBegan – Isso é chamado quando a tela é tocada pela primeira vez.
  • TouchesMoved – Isso é chamado quando o local do toque é alterado à medida que o usuário desliza os dedos ao redor da tela.
  • TouchesEnded ou TouchesCancelledTouchesEnded é chamado quando os dedos do usuário são retirados da tela. TouchesCancelled será chamado se o iOS cancelar o toque – por exemplo, se um usuário deslizar o dedo para longe de um botão para cancelar uma tecla.

Os eventos de toque percorrem recursivamente para baixo pela pilha de UIViews, para marcar se o evento de toque estiver dentro dos limites de um objeto de exibição. Isso geralmente é chamado de Teste de clique. Eles serão chamados primeiro na parte superior UIView ou UIViewController , em seguida, serão chamados UIView no e UIViewControllers abaixo deles na hierarquia de exibição.

Um UITouch objeto será criado sempre que o usuário tocar na tela. O UITouch objeto inclui dados sobre o toque, como quando o toque ocorreu, onde ocorreu, se o toque foi um deslize etc. Os eventos de toque são passados por uma propriedade de toques – um NSSet que contém um ou mais toques. Podemos usar essa propriedade para obter uma referência a um toque e determinar a resposta do aplicativo.

As classes que substituem um dos eventos de toque devem primeiro chamar a implementação base e, em seguida, obter o UITouch objeto associado ao evento. Para obter uma referência ao primeiro toque, chame a propriedade e converta-a AnyObject como uma UITouch conforme mostrado no exemplo a seguir:

public override void TouchesBegan (NSSet touches, UIEvent evt)
{
    base.TouchesBegan (touches, evt);
    UITouch touch = touches.AnyObject as UITouch;
    if (touch != null)
    {
        //code here to handle touch
    }
}

O iOS reconhece automaticamente toques rápidos sucessivos na tela e coletará todos eles como um toque em um único UITouch objeto. Isso torna a verificação de um toque duplo tão fácil quanto verificar a TapCount propriedade, conforme ilustrado no código a seguir:

public override void TouchesBegan (NSSet touches, UIEvent evt)
{
    base.TouchesBegan (touches, evt);
    UITouch touch = touches.AnyObject as UITouch;
    if (touch != null)
    {
        if (touch.TapCount == 2)
        {
            // do something with the double touch.
        }
    }
}

Multi-Touch

O multitoque não está habilitado por padrão em controles. O multitoque pode ser habilitado no Designer do iOS, conforme ilustrado pela captura de tela a seguir:

Multitoque habilitado no Designer do iOS

Também é possível definir vários toques programaticamente definindo a MultipleTouchEnabled propriedade conforme mostrado na seguinte linha de código:

imgTouchMe.MultipleTouchEnabled = true;

Para determinar quantos dedos tocaram na tela, use a Count propriedade na UITouch propriedade :

public override void TouchesBegan (NSSet touches, UIEvent evt)
{
    base.TouchesBegan (touches, evt);
    lblNumberOfFingers.Text = "Number of fingers: " + touches.Count.ToString();
}

Determinando o local de toque

O método UITouch.LocationInView retorna um objeto CGPoint que contém as coordenadas do toque em uma determinada exibição. Além disso, podemos testar para ver se esse local está dentro de um controle chamando o método Frame.Contains. O snippet de código a seguir mostra um exemplo disso:

if (this.imgTouchMe.Frame.Contains (touch.LocationInView (this.View)))
{
    // the touch event happened inside the UIView imgTouchMe.
}

Agora que temos uma compreensão dos eventos de toque no iOS, vamos aprender sobre reconhecedores de gestos.

Reconhecedores de Gestos

Os reconhecedores de gestos podem simplificar e reduzir muito o esforço de programação para dar suporte ao toque em um aplicativo. Os reconhecedores de gestos do iOS agregam uma série de eventos de toque em um único evento de toque.

O Xamarin.iOS fornece a classe UIGestureRecognizer como uma classe base para os seguintes reconhecedores de gestos internos:

  • UITapGestureRecognizer – isso é para um ou mais toques.
  • UIPinchGestureRecognizer – Pinçando e espalhando dedos separados.
  • UIPanGestureRecognizer – Movimento panorâmico ou arrastar.
  • UISwipeGestureRecognizer – passando o dedo em qualquer direção.
  • UIRotationGestureRecognizer – girar dois dedos em um movimento no sentido horário ou no sentido anti-horário.
  • UILongPressGestureRecognizer – pressione e segure, às vezes chamado de pressionamento longo ou clique longo.

O padrão básico para usar um reconhecedor de gestos é o seguinte:

  1. Criar uma instância do reconhecedor de gestos – primeiro, instancie uma UIGestureRecognizer subclasse. O objeto instanciado será associado por uma exibição e será coletado como lixo quando a exibição for descartada. Não é necessário criar essa exibição como uma variável de nível de classe.
  2. Definir qualquer configuração de gesto – a próxima etapa é configurar o reconhecedor de gestos. Consulte a documentação do Xamarin sobre UIGestureRecognizer e suas subclasses para obter uma lista de propriedades que podem ser definidas para controlar o comportamento de uma UIGestureRecognizer instância.
  3. Configurar o destino – devido à sua Objective-C herança, o Xamarin.iOS não gera eventos quando um reconhecedor de gestos corresponde a um gesto. UIGestureRecognizer tem um método – AddTarget – que pode aceitar um delegado anônimo ou um Objective-C seletor com o código a ser executado quando o reconhecedor de gestos faz uma correspondência.
  4. Habilitar o reconhecedor de gestos – assim como acontece com eventos de toque, os gestos só serão reconhecidos se as interações por toque estiverem habilitadas.
  5. Adicionar o reconhecedor de gestos ao modo de exibição – a etapa final é adicionar o gesto a um modo de exibição chamando View.AddGestureRecognizer e passando-lhe um objeto de reconhecimento de gestos.

Consulte os exemplos do reconhecedor de gestos para obter mais informações sobre como implementá-los no código.

Quando o destino do gesto for chamado, ele será passado uma referência ao gesto que ocorreu. Isso permite que o destino do gesto obtenha informações sobre o gesto ocorrido. A extensão das informações disponíveis depende do tipo de reconhecedor de gestos usado. Consulte a documentação do Xamarin para obter informações sobre os dados disponíveis para cada UIGestureRecognizer subclasse.

É importante lembrar que, depois que um reconhecedor de gestos for adicionado a um modo de exibição, o modo de exibição (e quaisquer exibições abaixo dele) não receberá nenhum evento de toque. Para permitir eventos de toque simultaneamente com gestos, a CancelsTouchesInView propriedade deve ser definida como false, conforme ilustrado pelo seguinte código:

_tapGesture.Recognizer.CancelsTouchesInView = false;

Cada UIGestureRecognizer um tem uma propriedade State que fornece informações importantes sobre o status do reconhecedor de gestos. Sempre que o valor dessa propriedade for alterado, o iOS chamará o método de assinatura, dando-lhe uma atualização. Se um reconhecedor de gestos personalizado nunca atualizar a propriedade State, o assinante nunca será chamado, tornando o reconhecedor de gestos inútil.

Gestos podem ser resumidos como um dos dois tipos:

  1. Discreto – esses gestos só disparam na primeira vez em que são reconhecidos.
  2. Contínuo – esses gestos continuam a disparar desde que sejam reconhecidos.

Reconhecedores de gestos existem em um dos seguintes estados:

  • Possível – esse é o estado inicial de todos os reconhecedores de gestos. Esse é o valor padrão da propriedade State.
  • Iniciado – quando um gesto contínuo é reconhecido pela primeira vez, o estado é definido como Iniciado. Isso permite que as assinaturas diferenciem entre quando o reconhecimento de gestos é iniciado e quando ele é alterado.
  • Alterado – depois que um gesto contínuo tiver começado, mas não tiver terminado, o estado será definido como Alterado sempre que um toque for movido ou alterado, desde que ainda esteja dentro dos parâmetros esperados do gesto.
  • Cancelado – esse estado será definido se o reconhecedor passou de Iniciado para Alterado e, em seguida, os toques foram alterados de forma a não se ajustar mais ao padrão do gesto.
  • Reconhecido – o estado será definido quando o reconhecedor de gestos corresponder a um conjunto de toques e informará ao assinante que o gesto foi concluído.
  • Encerrado – esse é um alias para o estado Reconhecido.
  • Falha – quando o reconhecedor de gestos não puder mais corresponder aos toques que está escutando, o estado será alterado para Falha.

O Xamarin.iOS representa esses valores na UIGestureRecognizerState enumeração .

Trabalhando com vários gestos

Por padrão, o iOS não permite que gestos padrão sejam executados simultaneamente. Em vez disso, cada reconhecedor de gestos receberá eventos de toque em uma ordem não determinística. O snippet de código a seguir ilustra como fazer um reconhecedor de gestos ser executado simultaneamente:

gesture.ShouldRecognizeSimultaneously += (UIGestureRecognizer r) => { return true; };

Também é possível desabilitar um gesto no iOS. Há duas propriedades delegadas que permitem que um reconhecedor de gestos examine o estado de um aplicativo e os eventos de toque atuais, para tomar decisões sobre como e se um gesto deve ser reconhecido. Os dois eventos são:

  1. ShouldReceiveTouch – esse delegado é chamado logo antes que o reconhecedor de gestos seja passado por um evento de toque e oferece uma oportunidade para examinar os toques e decidir quais toques serão tratados pelo reconhecedor de gestos.
  2. ShouldBegin – isso é chamado quando um reconhecedor tenta alterar o estado de Possível para algum outro estado. Retornar false forçará o estado do reconhecedor de gestos a ser alterado para Falha.

Você pode substituir esses métodos com um fortemente tipado UIGestureRecognizerDelegate, um delegado fraco ou associar por meio da sintaxe do manipulador de eventos, conforme ilustrado pelo seguinte snippet de código:

gesture.ShouldReceiveTouch += (UIGestureRecognizer r, UITouch t) => { return true; };

Por fim, é possível enfileirar um reconhecedor de gestos para que ele só tenha êxito se outro reconhecedor de gestos falhar. Por exemplo, um reconhecedor de gestos de toque único só deve ter êxito quando um reconhecedor de gestos de toque duplo falhar. O snippet de código a seguir fornece um exemplo disso:

singleTapGesture.RequireGestureRecognizerToFail(doubleTapGesture);

Criando um gesto personalizado

Embora o iOS forneça alguns reconhecedores de gestos padrão, pode ser necessário criar reconhecedores de gestos personalizados em determinados casos. A criação de um reconhecedor de gestos personalizado envolve as seguintes etapas:

  1. Subclasse UIGestureRecognizer .
  2. Substitua os métodos de evento de toque apropriados.
  3. O reconhecimento de bolhas status por meio da propriedade State da classe base.

Um exemplo prático disso será abordado no passo a passo Usando o Toque no iOS .