Introdução ao 3D Touch no Xamarin.iOS

Este artigo aborda o uso dos novos gestos do iPhone 6s e iPhone 6s Plus 3D Touch em seu aplicativo.

Exemplos de aplicativos habilitados para 3D Touch

Este artigo fornecerá uma introdução ao uso das novas APIs do 3D Touch para adicionar gestos sensíveis à pressão aos seus aplicativos Xamarin.iOS em execução nos novos dispositivos iPhone 6s e iPhone 6s Plus.

Com o 3D Touch, um aplicativo para iPhone agora é capaz não apenas de dizer que o usuário está tocando na tela do dispositivo, mas também de sentir quanta pressão o usuário está exercendo e responder aos diferentes níveis de pressão.

O 3D Touch fornece os seguintes recursos para seu aplicativo:

  • Sensibilidade à pressão - Os aplicativos agora podem medir o quão forte ou leve o usuário está tocando na tela e aproveitar essas informações. Por exemplo, um aplicativo de pintura pode tornar uma linha mais grossa ou mais fina com base na força com que o usuário está tocando na tela.
  • Peek and Pop - Seu aplicativo agora pode permitir que o usuário interaja com seus dados sem precisar sair do contexto atual. Ao pressionar com força na tela, eles podem espiar o item em que estão interessados (como visualizar uma mensagem). Ao pressionar com mais força, eles podem entrar no item.
  • Ações rápidas - Pense nas ações rápidas como os menus contextuais que podem ser exibidos quando um usuário clica com o botão direito do mouse em um item em um aplicativo da área de trabalho. Usando as Ações Rápidas, você pode adicionar atalhos para funções em seu aplicativo diretamente do ícone do aplicativo na tela inicial.
  • Testando o 3D Touch no Simulador - Com o hardware Mac correto, você pode testar aplicativos habilitados para 3D Touch no Simulador do iOS.

Sensibilidade à pressão

Conforme mencionado acima, usando novas propriedades da classe UITouch , você pode medir a quantidade de pressão que o usuário está aplicando à tela do dispositivo iOS e usar essas informações em sua interface do usuário. Por exemplo, tornar uma pincelada mais translúcida ou opaca com base na quantidade de pressão.

Uma pincelada renderizada como mais translúcida ou opaca com base na quantidade de pressão

Como resultado do 3D Touch, se o seu aplicativo estiver sendo executado no iOS 9 (ou superior) e o dispositivo iOS for compatível com o 3D Touch, as alterações na pressão farão com que o TouchesMoved evento seja gerado.

Por exemplo, ao monitorar o TouchesMoved evento de um UIView, você pode usar o seguinte código para obter a pressão atual que o usuário está aplicando à tela:

public override void TouchesMoved (NSSet touches, UIEvent evt)
{
    base.TouchesMoved (touches, evt);
    UITouch touch = touches.AnyObject as UITouch;
    if (touch != null)
    {
        // Get the pressure
        var force = touch.Force;
        var maxForce = touch.MaximumPossibleForce;

        // Do something with the touch and the pressure
        ...
    }
}

A MaximumPossibleForce propriedade retorna o valor mais alto possível para a Force propriedade do UITouch com base no dispositivo iOS em que o aplicativo está sendo executado.

Importante

Mudanças na pressão farão com que o TouchesMoved evento seja aumentado, mesmo que as coordenadas X/Y não tenham mudado. Devido a essa alteração no comportamento, seus aplicativos iOS devem estar preparados para que o TouchesMoved evento seja invocado com mais frequência e para que as coordenadas X/Y sejam as mesmas da última TouchesMoved chamada.

Para obter mais informações, consulte o TouchCanvas da Apple: usando o aplicativo de exemplo UITouch de forma eficiente e eficaz e a referência de classe UITouch.

Espiar e Pop

O 3D Touch oferece novas maneiras para um usuário interagir com as informações em seu aplicativo mais rápido do que nunca, sem precisar navegar a partir de sua localização atual.

Por exemplo, se o aplicativo estiver exibindo uma tabela de mensagens, o usuário poderá pressionar com força um item para visualizar seu conteúdo em um modo de exibição de sobreposição (que a Apple chama de Peek).

Um exemplo de espiada no conteúdo

Se o usuário pressionar com mais força, ele entrará na visualização de mensagem normal (que é conhecida como Pop-ping na visualização).

Verificando a disponibilidade do 3D Touch

Ao trabalhar com um UIViewController , você pode usar o seguinte código para ver se o dispositivo iOS em que o aplicativo está sendo executado é compatível com o 3D Touch:

public override void TraitCollectionDidChange(UITraitCollection previousTraitCollection)
{
    //Important: call the base function
    base.TraitCollectionDidChange(previousTraitCollection);

    //See if the new TraitCollection value includes force touch
    if (TraitCollection.ForceTouchCapability == UIForceTouchCapability.Available) {
        //Do something with 3D touch, for instance...
        RegisterForPreviewingWithDelegate (this, View);
        ...

Este método pode ser chamado antes ou depois ViewDidLoad().

Manipulando Peek e Pop

Em um dispositivo iOS que pode lidar com o UIViewControllerPreviewingDelegate 3D Touch, podemos usar uma instância da classe para lidar com a exibição dos detalhes do item Peek e Pop . Por exemplo, se tivéssemos um controlador de exibição de tabela chamado MasterViewController , poderíamos usar o seguinte código para dar suporte a Peek e Pop:

using System;
using System.Collections.Generic;
using UIKit;
using Foundation;
using CoreGraphics;

namespace DTouch
{
    public class PreviewingDelegate : UIViewControllerPreviewingDelegate
    {
        #region Computed Properties
        public MasterViewController MasterController { get; set; }
        #endregion

        #region Constructors
        public PreviewingDelegate (MasterViewController masterController)
        {
            // Initialize
            this.MasterController = masterController;
        }

        public PreviewingDelegate (NSObjectFlag t) : base(t)
        {
        }

        public PreviewingDelegate (IntPtr handle) : base (handle)
        {
        }
        #endregion

        #region Override Methods
        /// Present the view controller for the "Pop" action.
        public override void CommitViewController (IUIViewControllerPreviewing previewingContext, UIViewController viewControllerToCommit)
        {
            // Reuse Peek view controller for details presentation
            MasterController.ShowViewController(viewControllerToCommit,this);
        }

        /// Create a previewing view controller to be shown at "Peek".
        public override UIViewController GetViewControllerForPreview (IUIViewControllerPreviewing previewingContext, CGPoint location)
        {
            // Grab the item to preview
            var indexPath = MasterController.TableView.IndexPathForRowAtPoint (location);
            var cell = MasterController.TableView.CellAt (indexPath);
            var item = MasterController.dataSource.Objects [indexPath.Row];

            // Grab a controller and set it to the default sizes
            var detailViewController = MasterController.Storyboard.InstantiateViewController ("DetailViewController") as DetailViewController;
            detailViewController.PreferredContentSize = new CGSize (0, 0);

            // Set the data for the display
            detailViewController.SetDetailItem (item);
            detailViewController.NavigationItem.LeftBarButtonItem = MasterController.SplitViewController.DisplayModeButtonItem;
            detailViewController.NavigationItem.LeftItemsSupplementBackButton = true;

            // Set the source rect to the cell frame, so everything else is blurred.
            previewingContext.SourceRect = cell.Frame;

            return detailViewController;
        }
        #endregion
    }
}

O GetViewControllerForPreview método é usado para executar a operação Peek . Ele obtém acesso à célula da tabela e aos dados de backup e, em seguida, carrega o DetailViewController do Storyboard atual. Ao definir o PreferredContentSize como (0,0), estamos solicitando o tamanho padrão da visualização Peek . Por fim, desfocamos tudo, exceto a célula com a qual previewingContext.SourceRect = cell.Frame estamos exibindo e retornamos a nova visualização para exibição.

O CommitViewController reutiliza a exibição que criamos no Peek para a exibição Pop quando o usuário pressiona com mais força.

Registrando-se no Peek and Pop

No Controlador de Exibição do qual queremos permitir que o usuário inspecione e estoure itens, precisamos nos registrar para esse serviço. No exemplo dado acima de um Table View Controller (MasterViewController), usaríamos o seguinte código:

public override void ViewDidLoad ()
{
    base.ViewDidLoad ();

    // Check to see if 3D Touch is available
    if (TraitCollection.ForceTouchCapability == UIForceTouchCapability.Available) {
        // Register for Peek and Pop
        RegisterForPreviewingWithDelegate(new PreviewingDelegate(this), View);
    }
    ...

}

Aqui estamos chamando o RegisterForPreviewingWithDelegate método com uma instância do PreviewingDelegate que criamos acima. Em dispositivos iOS compatíveis com 3D Touch, o usuário pode pressionar com força um item para espiá-lo. Se eles pressionarem ainda mais, o item aparecerá na visualização de exibição padrão.

Para obter mais informações, consulte ViewControllerPreviews da Apple: usando o aplicativo de exemplo de APIs de visualização UIViewController, Referência de classe UIPreviewAction, Referência de classe UIPreviewActionGroup e Referência de protocolo UIPreviewActionItem.

Ações Rápidas

Usando o 3D Touch e as Ações Rápidas, você pode adicionar atalhos comuns, rápidos e fáceis de acessar para funções em seu aplicativo a partir do ícone da tela inicial no dispositivo iOS.

Como dito acima, você pode pensar em Ações Rápidas como os menus contextuais que podem ser exibidos quando um usuário clica com o botão direito do mouse em um item em um aplicativo da área de trabalho. Você deve usar Ações Rápidas para fornecer atalhos para as funções ou recursos mais comuns do seu aplicativo.

Um exemplo de um menu Ações Rápidas

Definindo ações rápidas estáticas

Se uma ou mais das Ações Rápidas exigidas pelo seu aplicativo forem estáticas e não precisarem ser alteradas Info.plist , você poderá defini-las no arquivo do aplicativo. Edite esse arquivo em um editor externo e adicione as seguintes chaves:

<key>UIApplicationShortcutItems</key>
<array>
    <dict>
        <key>UIApplicationShortcutItemIconType</key>
        <string>UIApplicationShortcutIconTypeSearch</string>
        <key>UIApplicationShortcutItemSubtitle</key>
        <string>Will search for an item</string>
        <key>UIApplicationShortcutItemTitle</key>
        <string>Search</string>
        <key>UIApplicationShortcutItemType</key>
        <string>com.company.appname.000</string>
    </dict>
    <dict>
        <key>UIApplicationShortcutItemIconType</key>
        <string>UIApplicationShortcutIconTypeShare</string>
        <key>UIApplicationShortcutItemSubtitle</key>
        <string>Will share an item</string>
        <key>UIApplicationShortcutItemTitle</key>
        <string>Share</string>
        <key>UIApplicationShortcutItemType</key>
        <string>com.company.appname.001</string>
    </dict>
</array>

Aqui estamos definindo dois itens estáticos de Ação Rápida com as seguintes chaves:

  • UIApplicationShortcutItemIconType - Define o ícone que será exibido pelo item Ação rápida como um dos seguintes valores:

    • UIApplicationShortcutIconTypeAdd
    • UIApplicationShortcutIconTypeAlarm
    • UIApplicationShortcutIconTypeAudio
    • UIApplicationShortcutIconTypeBookmark
    • UIApplicationShortcutIconTypeCapturePhoto
    • UIApplicationShortcutIconTypeCaptureVideo
    • UIApplicationShortcutIconTypeCloud
    • UIApplicationShortcutIconTypeCompose
    • UIApplicationShortcutIconTypeConfirmation
    • UIApplicationShortcutIconTypeContact
    • UIApplicationShortcutIconTypeDate
    • UIApplicationShortcutIconTypeFavorite
    • UIApplicationShortcutIconTypeHome
    • UIApplicationShortcutIconTypeInvitation
    • UIApplicationShortcutIconTypeLocation
    • UIApplicationShortcutIconTypeLove
    • UIApplicationShortcutIconTypeMail
    • UIApplicationShortcutIconTypeMarkLocation
    • UIApplicationShortcutIconTypeMessage
    • UIApplicationShortcutIconTypePause
    • UIApplicationShortcutIconTypePlay
    • UIApplicationShortcutIconTypeProhibit
    • UIApplicationShortcutIconTypeSearch
    • UIApplicationShortcutIconTypeShare
    • UIApplicationShortcutIconTypeShuffle
    • UIApplicationShortcutIconTypeTask
    • UIApplicationShortcutIconTypeTaskCompleted
    • UIApplicationShortcutIconTypeTime
    • UIApplicationShortcutIconTypeUpdate

    Imagens UIApplicationShortcutIconType

  • UIApplicationShortcutItemSubtitle - Define a legenda do item.

  • UIApplicationShortcutItemTitle - Define o título do item.

  • UIApplicationShortcutItemType - É um valor de string que usaremos para identificar o item em nosso aplicativo. Consulte a seção a seguir para mais informações.

Importante

Os itens de atalho de Ação Rápida definidos no Info.plist arquivo não podem ser acessados com a Application.ShortcutItems propriedade. Eles são passados apenas para o manipulador de HandleShortcutItem eventos.

Identificando itens de ação rápida

Como você viu acima, ao definir seus itens de Info.plistAção Rápida no , você atribuiu um valor de UIApplicationShortcutItemType string à chave para identificá-los.

Para facilitar o trabalho com esses identificadores no código, adicione uma classe chamada ShortcutIdentifier ao projeto do aplicativo e faça com que ela tenha a seguinte aparência:

using System;

namespace AppSearch
{
    public static class ShortcutIdentifier
    {
        public const string First = "com.company.appname.000";
        public const string Second = "com.company.appname.001";
        public const string Third = "com.company.appname.002";
        public const string Fourth = "com.company.appname.003";
    }
}

Manipulando uma ação rápida

Em seguida, você precisa modificar o arquivo do AppDelegate.cs aplicativo para que o usuário selecione um item de Ação Rápida no ícone do aplicativo na tela inicial.

Faça as seguintes edições:

using System;
...

public UIApplicationShortcutItem LaunchedShortcutItem { get; set; }

public bool HandleShortcutItem(UIApplicationShortcutItem shortcutItem) {
    var handled = false;

    // Anything to process?
    if (shortcutItem == null) return false;

    // Take action based on the shortcut type
    switch (shortcutItem.Type) {
    case ShortcutIdentifier.First:
        Console.WriteLine ("First shortcut selected");
        handled = true;
        break;
    case ShortcutIdentifier.Second:
        Console.WriteLine ("Second shortcut selected");
        handled = true;
        break;
    case ShortcutIdentifier.Third:
        Console.WriteLine ("Third shortcut selected");
        handled = true;
        break;
    case ShortcutIdentifier.Fourth:
        Console.WriteLine ("Forth shortcut selected");
        handled = true;
        break;
    }

    // Return results
    return handled;
}

public override bool FinishedLaunching (UIApplication application, NSDictionary launchOptions)
{
    var shouldPerformAdditionalDelegateHandling = true;

    // Get possible shortcut item
    if (launchOptions != null) {
        LaunchedShortcutItem = launchOptions [UIApplication.LaunchOptionsShortcutItemKey] as UIApplicationShortcutItem;
        shouldPerformAdditionalDelegateHandling = (LaunchedShortcutItem == null);
    }

    return shouldPerformAdditionalDelegateHandling;
}

public override void OnActivated (UIApplication application)
{
    // Handle any shortcut item being selected
    HandleShortcutItem(LaunchedShortcutItem);

    // Clear shortcut after it's been handled
    LaunchedShortcutItem = null;
}

public override void PerformActionForShortcutItem (UIApplication application, UIApplicationShortcutItem shortcutItem, UIOperationHandler completionHandler)
{
    // Perform action
    completionHandler(HandleShortcutItem(shortcutItem));
}

Primeiro, definimos uma propriedade pública LaunchedShortcutItem para rastrear o último item de Ação Rápida selecionado pelo usuário. Em seguida, substituímos o FinishedLaunching método e vemos se launchOptions foram passados e se eles contêm um item de Ação Rápida. Se o fizerem, armazenamos a LaunchedShortcutItem ação rápida na propriedade.

Em seguida, substituímos o OnActivated método e passamos qualquer item de Início Rápido selecionado para o HandleShortcutItem método a ser executado. No momento, estamos apenas escrevendo uma mensagem para o Console. Em um aplicativo real, você lidaria com qualquer ação necessária. Depois que a ação for tomada, a LaunchedShortcutItem propriedade será liberada.

Por fim, se seu aplicativo já estivesse em execução, o PerformActionForShortcutItem método seria chamado para lidar com o item Ação Rápida, portanto, precisamos substituí-lo e chamar nosso HandleShortcutItem método aqui também.

Criando itens de ação rápida dinâmicos

Além de definir itens de Ação Rápida estáticos no arquivo do seu aplicativo, você pode criar Ações Rápidas dinâmicas Info.plist em tempo real. Para definir duas novas Ações Rápidas dinâmicas, edite seu AppDelegate.cs arquivo novamente e modifique o FinishedLaunching método para que fique semelhante ao seguinte:

public override bool FinishedLaunching (UIApplication application, NSDictionary launchOptions)
{
    var shouldPerformAdditionalDelegateHandling = true;

    // Get possible shortcut item
    if (launchOptions != null) {
        LaunchedShortcutItem = launchOptions [UIApplication.LaunchOptionsShortcutItemKey] as UIApplicationShortcutItem;
        shouldPerformAdditionalDelegateHandling = (LaunchedShortcutItem == null);
    }

    // Add dynamic shortcut items
    if (application.ShortcutItems.Length == 0) {
        var shortcut3 = new UIMutableApplicationShortcutItem (ShortcutIdentifier.Third, "Play") {
            LocalizedSubtitle = "Will play an item",
            Icon = UIApplicationShortcutIcon.FromType(UIApplicationShortcutIconType.Play)
        };

        var shortcut4 = new UIMutableApplicationShortcutItem (ShortcutIdentifier.Fourth, "Pause") {
            LocalizedSubtitle = "Will pause an item",
            Icon = UIApplicationShortcutIcon.FromType(UIApplicationShortcutIconType.Pause)
        };

        // Update the application providing the initial 'dynamic' shortcut items.
        application.ShortcutItems = new UIApplicationShortcutItem[]{shortcut3, shortcut4};
    }

    return shouldPerformAdditionalDelegateHandling;
}

Agora estamos verificando se o application já contém um conjunto de criados ShortcutItemsdinamicamente, se não contém, criaremos dois novos UIMutableApplicationShortcutItem objetos para definir os novos itens e adicioná-los ao ShortcutItems array.

O código que já adicionamos na seção Manipulando uma ação rápida acima lidará com essas ações rápidas dinâmicas da mesma forma que as estáticas.

Deve-se notar que você pode criar uma mistura de itens de Ação Rápida estáticos e dinâmicos (como estamos fazendo aqui), você não está limitado a um ou outro.

Para obter mais informações, consulte ApplicationShortcuts da Apple: usando o aplicativo de exemplo UIApplicationShortcutItem , Referência de classe UIApplicationShortcutItem, Referência de classe UIMutableApplicationShortcutItem e Referência de classe UIApplicationShortcutIcon.

Testando o 3D Touch no simulador

Ao usar a versão mais recente do Xcode e do iOS Simulator em um Mac compatível com um trackpad habilitado para Force Touch, você pode testar a funcionalidade 3D Touch no Simulador.

Para ativar essa funcionalidade, execute qualquer aplicativo em hardware de iPhone simulado que suporte 3D Touch (iPhone 6s e superior). Em seguida, selecione o menu Hardware no Simulador do iOS e ative o item de menu Usar força do trackpad para toque 3D:

Selecione o menu Hardware no Simulador do iOS e ative o item de menu Usar força do trackpad para toque 3D

Com esse recurso ativo, você pode pressionar com mais força o trackpad do Mac para ativar o 3D Touch, assim como faria no hardware real do iPhone.

Resumo

Este artigo apresentou as novas APIs do 3D Touch disponibilizadas no iOS 9 para o iPhone 6s e iPhone 6s Plus. Abrangeu a adição de sensibilidade à pressão a um aplicativo; usando Peek e Pop para exibir rapidamente informações no aplicativo do contexto atual sem navegação; e usar Ações rápidas para fornecer atalhos para os recursos mais usados do seu aplicativo.