一、前言
3D Touch 是一种立体触控技术,被苹果称为新一代多点触控技术,是在Apple Watch 上采用的 Force Touch,屏幕可感应不同的感压力度触控。 3D Touch,苹果 iPhone 6s 的新功能,看起来类似 PC 上的右键。有 Peek 和 Pop 两种新手势。此功能的发布将手机屏幕的的操作坐标由 xy 轴扩大至 z 轴,增加了整整一个维度(即相对于多点触摸在平面二维空间的操作,3D Touch 技术增加了对力度和手指面积的感知,可以通过长按快速预览/查看你想要的短信/图片/超链接等内容,Peek 和 Pop 手势的响应时间可迅捷到 10ms 和 15ms),这在屏幕时代属于非常伟大的创新。
demo地址
二、苹果的3D Touch主要呈现方式
2.1、按功能划分,有三种:
- 主屏交互(
Home Screen Interaction); - 预览和跳转(
Peek and Pop); -
LivePhoto;
注:本文主要介绍一下前两种用法。
2.2、按3D Touch功能使用的位置划分,有两种:
-
手机桌面,效果图如下:
微信
京东
-
应用内,效果图如下:
微信
三、使用
3.1、主屏交互(Home Screen Interaction);
所谓的主屏交互也就是在手机的桌面,用手指按压应用图标,生成的几个快捷操作按钮的,效果图如下:
主屏交互的按钮有指定的模型类:
UIApplicationShortcutItem,添加 UIApplicationShortcutItem 有两种方式:静态添加和动态添加。
静态添加 和 动态添加 的 区别:静态设置是在应用安装的时候完成加载的,而动态设置需要在运行到对应代码时(runtime) 才加载,所以同时有静态加载的 Item 和动态加载的 Item时,静态加载的 Item 会排在前面。
3.1.1、静态添加UIApplicationShortcutItem
静态添加 UIApplicationShortcutItem 方式主要是在工程的 info.plist 文件中添加相关的属性,如下图:
// 数组中的元素就是上图中的快捷选项标签
UIApplicationShortcutItems
// 标签标题(必填)
UIApplicationShortcutItemTitle
// 标签的唯一标识 (必填)
UIApplicationShortcutItemType
// 使用系统图标的类型,如搜索、定位、home等(可选)
UIApplicationShortcutItemIconType
// 使用项目中的图片作为标签图标 (可选)
UIApplicationShortcutItemIconFile
// 标签副标题 (可选)
UIApplicationShortcutItemSubtitle
// 字典信息,如传值使用 (可选)
UIApplicationShortcutItemUserInfo
3.1.2、动态添加UIApplicationShortcutItem
UIApplicationShortcutItem 可以看作是 3D Touch 点击后,弹出菜单每行对应的模型,一行对应一个 UIApplicationShortcutItem 对象。
动态添加时就是我们可以通过生成 UIApplicationShortcutItem 对象数组,添加给 UIApplication 单例对象。
UIApplicationShortcutItem 初始方法如下:
/**
@param type item的唯一标识(必填)
@param localizedTitle 是item的标题(必填)
@param localizedSubtitle 是item的副标题(可选)
@param icon 是item的图标(可选)
@param userInfo 是item所包含的信息,类型是字典(可选)
*/
- (instancetype)initWithType:(NSString *)type
localizedTitle:(NSString *)localizedTitle
localizedSubtitle:(nullable NSString *)localizedSubtitle
icon:(nullable UIApplicationShortcutIcon *)icon
userInfo:(nullable NSDictionary<NSString *, id <NSSecureCoding>> *)userInfo;
初始化生成 UIApplicationShortcutItem 对象这一步操作一般都是在 AppDelegate 类的方法里处理的,方法如下:
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions;
动态添加时,首先要判断手机是否支持 3D Touch,代码如下:
if (self.window.traitCollection.forceTouchCapability == UIForceTouchCapabilityAvailable) {
// TODO - 创建3DTouch模型
}
生成 UIApplicationShortcutItem 对象数组,添加给 UIApplication 单例对象,示例代码如下:
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
// 首先判断是否支持3D Touch
if (self.window.traitCollection.forceTouchCapability == UIForceTouchCapabilityAvailable) {
// 创建3D Touch模型
[self setup3DTouch];
}
return YES;
}
- (void)setup3DTouch {
NSMutableArray *shortcutItems = (NSMutableArray *)[UIApplication sharedApplication].shortcutItems;
UIApplicationShortcutItem *shoreItem1 = [[UIApplicationShortcutItem alloc] initWithType:@"com.xw.test1" localizedTitle:@"test1" localizedSubtitle:@"sub test1" icon:[UIApplicationShortcutIcon iconWithType:UIApplicationShortcutIconTypeAdd] userInfo:nil];
UIApplicationShortcutItem *shortItem2 = [[UIApplicationShortcutItem alloc] initWithType:@"com.xw.test2" localizedTitle:@"test2" localizedSubtitle:@"sub test2" icon:[UIApplicationShortcutIcon iconWithTemplateImageName:@"like"] userInfo:nil];
[shortcutItems addObject:shoreItem1];
[shortcutItems addObject:shortItem2];
[UIApplication sharedApplication].shortcutItems = shortcutItems;
}
在使用动态添加 UIApplicationShortcutItem 时,可以使用自定义的图标(官方推荐一倍图使用 35x35 ),也可以使用系统图标,如下:
typedef NS_ENUM(NSInteger, UIApplicationShortcutIconType) {
UIApplicationShortcutIconTypeCompose,
UIApplicationShortcutIconTypePlay,
UIApplicationShortcutIconTypePause,
UIApplicationShortcutIconTypeAdd,
UIApplicationShortcutIconTypeLocation,
UIApplicationShortcutIconTypeSearch,
UIApplicationShortcutIconTypeShare,
UIApplicationShortcutIconTypeProhibit NS_ENUM_AVAILABLE_IOS(9_1),
UIApplicationShortcutIconTypeContact NS_ENUM_AVAILABLE_IOS(9_1),
UIApplicationShortcutIconTypeHome NS_ENUM_AVAILABLE_IOS(9_1),
UIApplicationShortcutIconTypeMarkLocation NS_ENUM_AVAILABLE_IOS(9_1),
UIApplicationShortcutIconTypeFavorite NS_ENUM_AVAILABLE_IOS(9_1),
UIApplicationShortcutIconTypeLove NS_ENUM_AVAILABLE_IOS(9_1),
UIApplicationShortcutIconTypeCloud NS_ENUM_AVAILABLE_IOS(9_1),
UIApplicationShortcutIconTypeInvitation NS_ENUM_AVAILABLE_IOS(9_1),
UIApplicationShortcutIconTypeConfirmation NS_ENUM_AVAILABLE_IOS(9_1),
UIApplicationShortcutIconTypeMail NS_ENUM_AVAILABLE_IOS(9_1),
UIApplicationShortcutIconTypeMessage NS_ENUM_AVAILABLE_IOS(9_1),
UIApplicationShortcutIconTypeDate NS_ENUM_AVAILABLE_IOS(9_1),
UIApplicationShortcutIconTypeTime NS_ENUM_AVAILABLE_IOS(9_1),
UIApplicationShortcutIconTypeCapturePhoto NS_ENUM_AVAILABLE_IOS(9_1),
UIApplicationShortcutIconTypeCaptureVideo NS_ENUM_AVAILABLE_IOS(9_1),
UIApplicationShortcutIconTypeTask NS_ENUM_AVAILABLE_IOS(9_1),
UIApplicationShortcutIconTypeTaskCompleted NS_ENUM_AVAILABLE_IOS(9_1),
UIApplicationShortcutIconTypeAlarm NS_ENUM_AVAILABLE_IOS(9_1),
UIApplicationShortcutIconTypeBookmark NS_ENUM_AVAILABLE_IOS(9_1),
UIApplicationShortcutIconTypeShuffle NS_ENUM_AVAILABLE_IOS(9_1),
UIApplicationShortcutIconTypeAudio NS_ENUM_AVAILABLE_IOS(9_1),
UIApplicationShortcutIconTypeUpdate NS_ENUM_AVAILABLE_IOS(9_1)
} API_AVAILABLE(ios(9.0)) API_UNAVAILABLE(tvos) API_UNAVAILABLE(macos);
3.1.3、监听主屏交互按钮的点击事件
设置好主屏交互的 item 后,我们剩下要做的就是在 app 内监听 item 的点击事件,此时需要用到之前设置 UIApplicationShortcutItemType 的唯一标示符,通过唯一标示符来判断用户点击了哪个 item,代码如下:
- (void)application:(UIApplication *)application
performActionForShortcutItem:(UIApplicationShortcutItem *)shortcutItem
completionHandler:(void (^)(BOOL))completionHandler {
// 不管APP在后台还是进程被杀死,只要通过主屏快捷操作进来的,都会调用这个方法
NSLog(@"\n\r localizedTitle:%@ \n\r type:%@", shortcutItem.localizedTitle, shortcutItem.type);
}
3.2、预览和跳转
Peek and Pop 在操作上是使用一定力度按压屏幕,触发 Peek 操作;在 Peek 状态下,上划唤出 Peek 快速操作( UIPreviewAction );Peek 状态下,再次用更大力度按压屏幕,转场到预览的控制器,效果如下图:
3.2.1、Peek and Pop使用的相关说明
-
UIViewControllerPreviewingDelegate:触发3D Touch的类,需要遵循该协议,并要实现协议中的方法; -
UIPreviewAction:Peek状态下,上划唤出快速操作选项实例; -
previewActionItems:Peek状态下,上划唤出快速操作选项实例数组。在要被Pop出的控制器中覆写get方法,返回一个UIPreviewAction数组。
3.2.2、Peek and Pop使用步骤
3.2.2.1、遵循协议,并注册代理
遵循 UIViewControllerPreviewingDelegate 协议,并在遵循 UIViewControllerPreviewingDelegate 协议的控制器中调用方法,方法如下:
- (id <UIViewControllerPreviewing>)registerForPreviewingWithDelegate:(id<UIViewControllerPreviewingDelegate>)delegate sourceView:(UIView *)sourceView;
- 遵循协议
@interface ViewController () <UIViewControllerPreviewingDelegate>
@end
- 注册代理,并传入响应
3D Touch的视图,下面是部分代码:
// 判断是否支持3D Touch
if (self.traitCollection.forceTouchCapability == UIForceTouchCapabilityAvailable) {
// 注册代理,并传入响应3D Touch的视图
[self registerForPreviewingWithDelegate:self sourceView:cell];
}
3.2.2.2、 实现UIViewControllerPreviewingDelegate协议的两个方法
- 当系统检测到
3D Touch时,它会调用previewingContext:viewControllerForLocation代理方法,传递一个符合UIViewControllerPreviewing协议的previewingContext对象。使用此方法配置并返回一个视图控制器以进行预览。
- (nullable UIViewController *)previewingContext:(nonnull id<UIViewControllerPreviewing>)previewingContext viewControllerForLocation:(CGPoint)location {
NSLog(@"%@", NSStringFromCGPoint(location));
UITableViewCell *cell = (UITableViewCell *)previewingContext.sourceView;
NSIndexPath *indexPath = [self.tableView indexPathForCell:cell];
XWTestViewController *vc = [[XWTestViewController alloc] init];
vc.index = (indexPath.row % 2 == 0 ? 0 : 1);
// 调整不被虚化的范围,按压的那个cell不被虚化(轻轻按压时周边会被虚化,再少用力展示预览,再加力跳页至设定界面)
// CGRect rect = CGRectMake(0, 0, self.view.frame.size.width,200);
// previewingContext.sourceRect = rect;
return vc;
}
- 当系统察觉到足够的压力可以触发
3D Touch而Pop出ViewController时,会调用previewingContext:commitViewController:代理方法:
- (void)previewingContext:(id<UIViewControllerPreviewing>)previewingContext commitViewController:(UIViewController *)viewControllerToCommit {
NSLog(@"%s", __func__);
[self showViewController:viewControllerToCommit sender:self];
// [self.navigationController pushViewController:viewControllerToCommit animated:YES];
}
3.2.2.3、 添加Peek状态下,上划时的快速操作
如果我们想在预览的时候,想做一些操作,那我们可以在 Peek 状态下,添加一些 Action 或者 Group,以提供快速操作。要添加快速操作,需要在预览控制器中重写 - (NSArray<id<UIPreviewActionItem>> *)previewActionItems 方法,示例代码如下:
- (NSArray<id<UIPreviewActionItem>> *)previewActionItems {
UIPreviewAction *action1 = [UIPreviewAction actionWithTitle:@"收藏" style:UIPreviewActionStyleDefault handler:^(UIPreviewAction * _Nonnull action, UIViewController * _Nonnull previewViewController) {
NSLog(@"收藏");
}];
UIPreviewAction *action2 = [UIPreviewAction actionWithTitle:@"分享" style:UIPreviewActionStyleDefault handler:^(UIPreviewAction * _Nonnull action, UIViewController * _Nonnull previewViewController) {
NSLog(@"分享");
}];
NSArray *actions = @[action1,action2];
return actions;
}
至此,3D Touch 关于 主屏交互、预览和跳转(Peek and Pop) 的内容就到此结束,LivePhoto的内容开发中很少用到,所以就略去了,后续有时间的话,会专门写一篇关于 LivePhoto 的文章补上。
四、Author
如果你有什么建议,可以关注我的公众号:iOS开发者进阶,直接留言,留言必回。










网友评论