Xamarin.iOS 中的 3D Touch 简介
本文介绍如何在应用中使用新的 iPhone 6s 和 iPhone 6s Plus 3D Touch 手势。
本文介绍如何使用新的 3D Touch API 为在新 iPhone 6s 和 iPhone 6s Plus 设备上运行的 Xamarin.iOS 应用添加压力敏感手势。
借助 3D Touch,iPhone 应用现在不仅能够判断用户是否在触摸设备屏幕,还可以感知用户施加的压力并对不同的压力级别做出响应。
3D Touch 为应用提供以下功能:
- 压力感应 - 应用现在可以测量用户触摸屏幕的力度并利用该信息。 例如,绘画应用可以根据用户触摸屏幕的力度来使线条变粗或变细。
- 轻瞄和突显 - 应用现在可以让用户与其数据交互,而无需离开当前上下文。 通过用力按压屏幕,他们可以使用速览来预览感兴趣的项(例如预览消息)。 如果再用力按压,则可使用弹出来展开该项。
- 快速操作 - 将快速操作想象为上下文菜单,当用户右键单击桌面应用中的项时,可以弹出这些菜单。 使用快速操作,可以直接从主屏幕上的应用图标为应用中的功能添加快捷方式。
- 在模拟器中测试 3D Touch - 使用正确的 Mac 硬件,可以在 iOS 模拟器中测试已启用 3D Touch 的应用。
压力敏感度
如上所述,通过使用 UITouch 类的新属性,可以测量用户施加在 iOS 设备屏幕上的压力,并在用户界面中使用此信息。 例如,根据压力大小使画笔笔划变得更加透明或更不透明。
得益于 3D Touch,如果你的应用在 iOS 9(或更高版本)上运行,并且 iOS 设备能够支持 3D Touch,则压力的变化将导致引发 TouchesMoved
事件。
例如,在监视 UIView 的 TouchesMoved
事件时,可以使用以下代码获取用户施加在屏幕上的当前压力:
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 称之为“速览”)。
如果用户更用力地按压,他们将进入常规消息视图(这称为弹出展开视图)。
检查 3D Touch 可用性
使用 UIViewController
时,可以使用以下代码查看运行应用的 iOS 设备是否支持 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);
...
此方法可以在之前或之后ViewDidLoad()
调用。
处理速览和弹出
在可处理 3D Touch 的 iOS 设备上,可以使用 UIViewControllerPreviewingDelegate
类的实例来处理速览和弹出项详细信息的显示。 例如,如果我们有一个被称为 MasterViewController
的表视图控制器,则可以使用以下代码来支持速览和弹出:
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
会将我们在速览中创建的视图重用于弹出视图。
注册速览和弹出
在我们希望允许用户从中速览和弹出项的视图控制器中,我们需要注册此服务。 在表视图控制器的上述示例中 (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 设备上,用户可以用力按压某个项来速览它。 如果他们更用力地按压,该项将弹出展开到标准显示视图中。
有关详细信息,请参阅 Apple 的 ViewControllerPreviews:使用 UIViewController 预览 API 示例应用、UIPreviewAction 类引用、UIPreviewActionGroup 类引用和 UIPreviewActionItem 协议引用。
快速操作
使用 3D Touch 和快速操作,可以从 iOS 设备上的主屏幕图标为应用中的功能添加常用、快速且易于访问的快捷方式。
如上所述,你可以将快速操作想象为上下文菜单,当用户右键单击桌面应用中的项时,就可以弹出这些菜单。 应使用快速操作来提供应用的常见功能的快捷方式。
定义静态快速操作
如果应用所需的一个或多个快速操作是静态的,并且不需要更改,则可以在应用的 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
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
数组中。
在上面的处理快速操作部分中添加的代码将处理这些动态快速操作,就像处理静态操作一样。
应注意的是,可以混合创建静态和动态快速操作项(正如我们在此处执行的操作),而不必局限于某一种操作项。
有关详细信息,请参阅 Apple 的 ApplicationShortcuts:使用 UIApplicationShortcutItem 示例应用、UIApplicationShortcutItem 类引用、UIMutableApplicationShortcutItem 类引用和 UIApplicationShortcutIcon 类引用。
在模拟器中测试 3D Touch
在带有 Force Touch 启用触控板的兼容 Mac 上使用最新版本的 Xcode 和 iOS 模拟器时,可以在模拟器中测试 3D Touch 功能。
若要启用此功能,请在支持 3D Touch 的模拟 iPhone 硬件(iPhone 6s 和更新机型)中运行任何应用。 接下来,在 iOS 模拟器中选择“硬件”菜单,并启用“为 3D Touch 使用 Trackpad Force”菜单项:
启用此功能后,可以在 Mac 的触控板上更用力地按压以启用 3D Touch,就像在真正的 iPhone 硬件上操作一样。
总结
本文介绍了 iOS 9 中为 iPhone 6s 和 iPhone 6s Plus 提供的新 3D Touch API。 其中介绍了向应用添加压力敏感度;使用速览和弹出快速显示当前上下文中的应用内信息(无需导航);使用快速操作提供应用常用功能的快捷方式。