3D Touch 作为苹果新出的一个功能, 从开发上面来讲, 还是很简单的, 毕竟是是新功能嘛. 这不是闲着没事, 看了一下, 顺便写个demo, 让更多的人更容易的学习.
3D Touch 可以做的事情:
- icon的菜单
- 静态菜单
- 动 态菜单
- 相应菜单的点击事件, 并做相关的动作
- peek和pop
- peek 轻摁预览下个控制器
- pop 重摁跳转到下个控制器
- peek期间自定义的操作
- force属性
如下所示:
重摁弹出快捷菜单, 这种菜单分为 静态菜单和动态菜单, 创建方式和效果有所区别. 静态菜单通过plist来创建, 在应用第一次安装到手机上未打开过之前就可以使用, 静态菜单在应用运行期间是不会发生变化的; 动态菜单在应用在手机上打开过一次之后可以使用, 是在AppDelegate中通过代码创建的, 在用户安装到手机上之后, 是可以通过改变菜单内容的, 比如通讯录可以做成, 动态菜单展示最近拨打过的电话. 两种菜单最多可以创建四个, 如果一个应用既有静态菜单也有动态菜单, 静态菜单总是会摆放在靠近icon的位置.
动态菜单和静态菜单点击事件都是在 application: performActionForShortcutItem: completionHandler: 这个方法中监听并实现事件处理和跳转的.
如下图所示, 创建静态菜单, 可以配置的有五个属性,
IApplicationShortcutItems // 配置plist时候, 所有子项目需要放在这个键的字典下面
UIApplicationShortcutItemType // 必须有, 可以为空, 用来区别不同的icon
UIApplicationShortcutItemTitle // 必须有, 可以用来区别不同的icon
UIApplicationShortcutItemSubtitle // 非必须, 子标题
UIApplicationShortcutItemIconType // 非必须, 使用系统图标的样式
UIApplicationShortcutItemIconFile // 非必须, 使用的icon文件
创建动态菜单的代码如下所示, UIApplicationShortcutItem
类还是比较简单的, 可以看看api或者官方文档上面的解释. 创建动态菜单需要在 application:didFinishLaunchingWithOptions:
中创建.
- (void)createShortCutItems
{
UIApplicationShortcutIcon *icon1 = [UIApplicationShortcutIcon iconWithType:UIApplicationShortcutIconTypeAlarm];
UIApplicationShortcutIcon *icon2 = [UIApplicationShortcutIcon iconWithType:UIApplicationShortcutIconTypeAudio];
UIApplicationShortcutIcon *icon3 = [UIApplicationShortcutIcon iconWithType:UIApplicationShortcutIconTypeBookmark];
UIApplicationShortcutItem *item1 = [[UIApplicationShortcutItem alloc] initWithType:@"first" localizedTitle:@"first item" localizedSubtitle:@"第一个" icon:icon1 userInfo:nil];
UIApplicationShortcutItem *item2 = [[UIApplicationShortcutItem alloc] initWithType:@"second" localizedTitle:@"second item" localizedSubtitle:@"第二个" icon:icon2 userInfo:nil];
UIApplicationShortcutItem *item3 = [[UIApplicationShortcutItem alloc] initWithType:@"third" localizedTitle:@"third item" localizedSubtitle:@"第三个" icon:icon3 userInfo:nil];
NSArray *newArray = @[item1, item2, item3];
[UIApplication sharedApplication].shortcutItems = newArray;
}
当点击 Home Screen Quick Actions 进入应用的时候, 会走这个方法, 不管应用是否在杀死状态, 都会走这个方法(已测试).
在这个方法里面对点击事件的进行处理, 做相应的操作. 比如, 跳转到指定的页面.
- (void)application:(UIApplication *)application performActionForShortcutItem:(UIApplicationShortcutItem *)shortcutItem completionHandler:(void (^)(BOOL))completionHandler
{
NSString *itemType = shortcutItem.type;
if ([itemType isEqualToString:@"first"]) {
NSLog(@"点击了第一个");
}
else if ([itemType isEqualToString:@"second"]) {
NSLog(@"点击了第二个");
}
else if ([itemType isEqualToString:@"third"]) {
NSLog(@"点击了第三个");
}
else if ([itemType isEqualToString:@"forth"]) {
NSLog(@"点击了第四个");
}
UIAlertView *alert = [[UIAlertView alloc] initWithTitle:@"" message:itemType delegate:nil cancelButtonTitle:@"确定" otherButtonTitles: nil];
[alert show];
}
首先 peek 和 pop 的操作是在UIViewControllerPreviewingDelegate
这个代理的代理方法中处理的, 所以需要遵循这个代理方法.
把需要支持peek的view注册一下:
// 判断控制器是否支持3DTouch
if (self.traitCollection.forceTouchCapability == UIForceTouchCapabilityAvailable) {
// 注册支持3DTouch的视图:cell,并设置代理
// @interface ViewController () <UIViewControllerPreviewingDelegate>
[self registerForPreviewingWithDelegate:self sourceView:cell];
}
在这个方法里面要返回要peek的控制器, 如果是UITableView, 需要去计算点击的位置, 拿到数据源.
// If you return nil, a preview presentation will not be performed
- (nullable UIViewController *)previewingContext:(id <UIViewControllerPreviewing>)previewingContext viewControllerForLocation:(CGPoint)location NS_AVAILABLE_IOS(9_0)
{
// 计算点击的cell的indexPath
location = [self.tableView convertPoint:location fromView:[previewingContext sourceView]];
NSIndexPath *path = [self.tableView indexPathForRowAtPoint:location];
SecondViewController *secondVC = [[SecondViewController alloc] init];
secondVC.content = self.dataArray[path.row];
// secondVC.preferredContentSize = CGSizeMake(0, 200); // 只能设置高度,宽度是固定的, 这里除了设置高度, 还可以设置很多其他的属性, 详见api
// vc.view.backgroundColor = [UIColor greenColor]; // 在这里可以对 viewController 进行一些基本的设置
return secondVC;
}
pop操作就更简单了, 在这个方法里面, 返回要pop的控制器即可.
- (void)previewingContext:(id <UIViewControllerPreviewing>)previewingContext commitViewController:(UIViewController *)viewControllerToCommit NS_AVAILABLE_IOS(9_0)
{
[self presentViewController:viewControllerToCommit animated:YES completion:nil];// 动画是无效的
}
需要在- (NSArray<id<UIPreviewActionItem>> *)previewActionItems
方法中返回包含UIPreviewAction
的数组, 具体代码如下所示.
// 使用懒加载的数组.
- (NSArray *)preActions
{
UIPreviewAction *action1 = [UIPreviewAction actionWithTitle:@"大赞" style:UIPreviewActionStyleDefault handler:^(UIPreviewAction * _Nonnull action, UIViewController * _Nonnull previewViewController) {
NSLog(@"你点击了 大赞");
}];
UIPreviewAction *action2 = [UIPreviewAction actionWithTitle:@"中赞" style:UIPreviewActionStyleDestructive handler:^(UIPreviewAction * _Nonnull action, UIViewController * _Nonnull previewViewController) {
NSLog(@"你点击了 中赞");
}];
UIPreviewAction *action3 = [UIPreviewAction actionWithTitle:@"小赞" style:UIPreviewActionStyleSelected handler:^(UIPreviewAction * _Nonnull action, UIViewController * _Nonnull previewViewController) {
NSLog(@"你点击了 小赞");
}];
NSArray *actions = @[action1, action2, action3];
UIPreviewActionGroup *actionsGroup = [UIPreviewActionGroup actionGroupWithTitle:@"怎么赞呢?" style:UIPreviewActionStyleDefault actions:actions];
return @[actionsGroup];
}
// 这个方法的返回值, 才是会显示的组, 本例使用懒加载加载数据.
- (NSArray<id<UIPreviewActionItem>> *)previewActionItems
{
return self.preActions;
}
UITouch和UIPress新增了force属性, 是一个float类型的值, 代表摁压的力度, 数值越大, 标示摁压的力度越大, iPhone 6s 测试最大值是: 6.666667 .
UITouch *touch = [touches anyObject];
NSLog(@"touch force = %f", touch.force);
发现系统的邮箱在peek时候还有左右滑动的操作, 目前还不知道这个是怎么实现的,, 如果谁知道请钙素我一下
3DTouch, peek时候, 左右滑动做不同的操作这个是怎么实现的 ?