Xamarin.iOS 中的 3D Touch 简介

本文介绍如何在应用中使用新的 i电话 6s 和 i电话 6s Plus 3D 触控手势。

Examples of 3D Touch enabled apps

本文介绍如何使用新的 3D Touch API 为在新 iPhone 6s 和 iPhone 6s Plus 设备上运行的 Xamarin.iOS 应用添加压力敏感手势。

使用 3D Touch 时,i电话 应用现在不仅能够告知用户正在触摸设备的屏幕,而且能够感知用户施加的压力,并响应不同的压力级别。

3D Touch 为应用提供以下功能:

  • 压力感应 - 应用现在可以测量用户触摸屏幕的力度并利用该信息。 例如,绘画应用可以根据用户触摸屏幕的力度来使线条变粗或变细。
  • 轻瞄和突显 - 应用现在可以让用户与其数据交互,而无需离开当前上下文。 通过在屏幕上按硬键,他们可以查看他们感兴趣的项目(如预览消息)。 通过更努力地按下,他们可以弹出项。
  • 快速操作 - 将快速操作想象为上下文菜单,当用户右键单击桌面应用中的项时,可以弹出这些菜单。 使用快速操作,可以直接从主屏幕上的应用图标向应用中的函数添加快捷方式。
  • 在模拟器 中测试 3D Touch - 使用正确的 Mac 硬件,可以在 iOS 模拟器中测试已启用 3D Touch 的应用。

压力敏感度

如上所述,通过使用 UITouch 类的新属性,可以测量用户应用于 iOS 设备的屏幕的压力量,并在用户界面中使用此信息。 例如,根据压力量使画笔笔划更半透明或不透明。

A brush stroke rendered as more translucent or opaque based on the amount of pressure

由于 3D Touch,如果应用在 iOS 9(或更高版本)上运行,并且 iOS 设备能够支持 3D Touch,则压力的变化将导致 TouchesMoved 引发事件。

例如,监视 TouchesMoved UIView 事件时,可以使用以下代码获取用户应用于屏幕的当前压力:

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

MaximumPossibleForce属性根据运行应用的 iOS 设备返回 UITouch 属性的最高可能值Force

重要

即使 X/Y 坐标未更改,压力的变化也会引发 TouchesMoved 事件。 由于此行为更改,iOS 应用应准备好 TouchesMoved 让事件更频繁地调用,并且 X/Y 坐标与上次 TouchesMoved 调用相同。

有关详细信息,请参阅 Apple 的 TouchCanvas:高效有效地 使用 UITouch 示例应用和 UITouch 类参考

速览和流行

3D Touch 为用户提供比以往更快地与应用中的信息交互的新方法,而无需从其当前位置导航。

例如,如果你的应用显示一个消息表,则用户可以对某个项目进行硬压,以在覆盖视图中预览其内容(Apple 指的是 “速览”)。

An example of Peeking at content

如果用户更努力地按下,他们将进入常规消息视图(这称为 “弹出 ping”进入视图)。

检查 3D 触控可用性

使用 A UIViewController 时,可以使用以下代码查看应用是否在 3D Touch 上运行的 iOS 设备:

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

此方法可以在之前 或之后ViewDidLoad()调用。

处理速览和 Pop

在可处理 3D Touch 的 iOS 设备上,可以使用类的UIViewControllerPreviewingDelegate实例来处理速览Pop 项详细信息的显示。 例如,如果调用 MasterViewController 了表视图控制器,可以使用以下代码来支持 速览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
    }
}

该方法 GetViewControllerForPreview 用于执行 速览 操作。 它获取对表单元格和支持数据的访问权限,然后从当前情节提要加载 DetailViewController 数据。 通过设置 PreferredContentSize 到 (0,0),我们要求使用默认 的“速览 ”视图大小。 最后,我们模糊显示 previewingContext.SourceRect = cell.Frame 的所有单元格,并返回用于显示的新视图。

当用户更努力地按下时,将CommitViewController重复使用我们在 Pop 视图的“速览”中创建的视图。

注册“速览”和“流行”

从我们希望允许用户 从中查看弹出 项的视图控制器中,我们需要注册此服务。 在上面给定的表视图控制器(MasterViewController)示例中,我们将使用以下代码:

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

}

在这里,我们将使用上面创建的实例PreviewingDelegate调用RegisterForPreviewingWithDelegate该方法。 在支持 3D Touch 的 iOS 设备上,用户可以硬压某个项目来查看它。 如果他们更难按,则项目将弹出到标准显示视图中。

有关详细信息,请参阅 iOS 9 ApplicationShortcuts 示例和 Apple 的 ViewControllerPreviews:使用 UIViewController 预览 API 示例应用、UIPreviewAction 类参考、UIPreviewActionGroup 类引用UIPreviewActionItem 协议参考

快速操作

使用 3D 触摸和快速操作,你可以从 iOS 设备上的主屏幕图标添加常用、快速且易于访问应用中函数的快捷方式。

如上所述,可以将快速操作视为上下文菜单,当用户右键单击桌面应用中的某个项时,可以弹出这些菜单。 应使用快速操作来提供应用的最常见函数或功能的快捷方式。

An example of a Quick Actions menu

定义静态快速操作

如果应用的一个或多个快速操作是静态的,并且不需要更改,则可以在应用的 Info.plist 文件中定义它们。 在外部编辑器中编辑此文件并添加以下键:

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

下面我们将使用以下键定义两个静态快速操作项:

  • UIApplicationShortcutItemIconType - 定义“快速操作”项将显示为以下值之一的图标:

    • 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

    UIApplicationShortcutIconType imagery

  • UIApplicationShortcutItemSubtitle - 定义项目的副标题。

  • UIApplicationShortcutItemTitle - 定义项的标题。

  • UIApplicationShortcutItemType - 是一个字符串值,用于标识应用中的项。 有关详细信息,请参阅下一节。

重要

无法使用属性访问Application.ShortcutItems文件中设置的Info.plist快速操作快捷项。 它们仅传递到 HandleShortcutItem 事件处理程序。

识别快速操作项

如上所示,在应用中 Info.plist定义快速操作项时,为密钥分配了一个字符串值 UIApplicationShortcutItemType 来标识它们。

若要使这些标识符更易于在代码中使用,请将调用 ShortcutIdentifier 的类添加到应用的项目中,使其如下所示:

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

处理快速操作

接下来,需要修改应用 AppDelegate.cs 的文件,以处理用户在主屏幕上的应用图标中选择快速操作项。

进行以下编辑:

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

首先,我们定义一个公共 LaunchedShortcutItem 属性,用于跟踪用户最后一个选定的快速操作项。 然后,我们将重写该方法 FinishedLaunching ,并查看是否已传递,以及它们是否 launchOptions 包含快速操作项。 如果这样做,我们会将快速操作存储在属性中 LaunchedShortcutItem

接下来,我们将重写该方法 OnActivated ,并将任何选定的快速启动项传递给 HandleShortcutItem 要对其执行操作的方法。 目前,我们只向控制台写入消息。 在实际应用中,你将处理所需的操作。 执行操作后,将清除该 LaunchedShortcutItem 属性。

最后,如果应用已运行,将调用该方法来处理快速操作项, PerformActionForShortcutItem 因此我们需要重写它并在此处调用方法 HandleShortcutItem

创建动态快速操作项

除了在应用的 Info.plist 文件中定义静态快速操作项之外,还可以创建动态动态快速操作。 若要定义两个新的动态快速操作,请再次编辑 AppDelegate.cs 文件并修改方法 FinishedLaunching ,如下所示:

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

现在,我们将检查查看application是否已包含一组动态创建的动态创建ShortcutItems对象,如果不创建两个新UIMutableApplicationShortcutItem对象来定义新项并将其添加到ShortcutItems数组中。

在上面的“处理快速操作”部分中添加的代码将处理这些动态快速操作,就像静态操作一样。

应注意的是,可以创建静态和动态快速操作项的混合体(正如我们在此处执行的操作),您不限于一项或另一项。

有关详细信息,请参阅 iOS 9 ViewControllerPreview 示例并查看 Apple 的 ApplicationShortcuts:使用 UIApplicationShortcutItem 示例应用、UIApplicationShortcutItem 类参考UIMutableApplicationShortcutItem 类引用和 UIApplicationShortcutIcon 类引用

在模拟器中测试 3D 触控

在兼容 Mac 上使用最新版本的 Xcode 和 iOS 模拟器与 Force Touch 启用触控板时,可以在模拟器中测试 3D Touch 功能。

若要启用此功能,请在支持 3D Touch(i电话 6 和更高版本)的模拟 i电话 硬件中运行任何应用。 接下来,选择 iOS 模拟器中的“硬件”菜单,并为 3D 触摸菜单项启用“使用触控板强制”:

Select the Hardware menu in the iOS Simulator and enable the Use Trackpad Force for 3D touch menu item

如果此功能处于活动状态,可以在 Mac 的触控板上更努力地按下,以像在实际 i电话 硬件上一样启用 3D Touch。

总结

本文介绍了 iOS 9 中为 i电话 6s 和 i电话 6s Plus 提供的新 3D 触控 API。 其中介绍了向应用添加压力敏感度;使用“速览”和“弹出”快速显示当前上下文中的应用内信息,而无需导航;使用快速操作提供应用最常用的功能的快捷方式。