一、前言
3D Touch
是一种立体触控技术,被苹果称为新一代多点触控技术,是在Apple Watch
上采用的 Force Touch
,屏幕可感应不同的感压力度触控。 3D Touch
,苹果 iPhone 6s
的新功能,看起来类似 PC
上的右键。有 Peek
和 Pop
两种新手势。此功能的发布将手机屏幕的的操作坐标由 xy
轴扩大至 z
轴,增加了整整一个维度(即相对于多点触摸在平面二维空间的操作,3D Touch
技术增加了对力度和手指面积的感知,可以通过长按快速预览/查看你想要的短信/图片/超链接等内容,Peek
和 Pop
手势的响应时间可迅捷到 10ms
和 15ms
),这在屏幕时代属于非常伟大的创新。
二、苹果的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开发者进阶
,直接留言,留言必回。