Light's Blog

The best or nothing.

3D Touch

| Comments

3D Touch简介

3D Touch是智能手机领域最先进技术之一,目前只有Apple在iPhone上构建了相对良好的生态,并在最新推出的iOS 10中进一步优化了用户体验,Android系统和手机厂商还未提供较为成熟的支持。 本文主要介绍3D Touch相关技术的基本实现方法,包括:

1、Home Screen Quick Actions,主屏幕快捷访问;

2、Peek and Pop,预览和进入;

3、3D Touch Force,3D touch压力值运用。

Home Screen Quick Action

显示效果

在主屏幕按下应用图标,会弹出设定好的快捷访问入口。本文采用纯代码创建,也可以通过设置Info.plist实现。

代码实现

首先,在AppDelegate.mapplication:didFinishLaunchingWithOptions:方法中添加UIApplicationShortcutItems

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
- (BOOL)application:(UIApplication *)application
    didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
  // Override point for customization after application launch.
  //  主界面入口
  ViewController *vc = [[ViewController alloc] init];
  self.mainNav = [[UINavigationController alloc] initWithRootViewController:vc];
  self.window.rootViewController = self.mainNav;

  //  创建快捷访问Items
  UIApplicationShortcutIcon *icon1 = [UIApplicationShortcutIcon
      iconWithType:UIApplicationShortcutIconTypeTask];
  UIApplicationShortcutItem *item1 =
      [[UIApplicationShortcutItem alloc] initWithType:@"item1"
                                       localizedTitle:@"item1"
                                    localizedSubtitle:@"1"
                                                 icon:icon1
                                             userInfo:nil];
  UIApplicationShortcutIcon *icon2 = [UIApplicationShortcutIcon
      iconWithType:UIApplicationShortcutIconTypeMail];
  UIApplicationShortcutItem *item2 =
      [[UIApplicationShortcutItem alloc] initWithType:@"item2"
                                       localizedTitle:@"item2"
                                    localizedSubtitle:@"2"
                                                 icon:icon2
                                             userInfo:nil];
  //  添加快捷访问Items
  application.shortcutItems = @[ item1, item2 ];
  return YES;
}

然后,在AppDelegate.m中添加如下方法,用于响应快捷访问事件。

1
2
3
4
5
6
7
8
9
10
11
12
13
- (void)application:(UIApplication *)application
    performActionForShortcutItem:(UIApplicationShortcutItem *)shortcutItem
               completionHandler:(void (^)(BOOL))completionHandler {
  //  响应Item对应的操作,跳转至对应controller
  if ([shortcutItem.type isEqualToString:@"item1"]) {
    Item1ViewController *vc = [[Item1ViewController alloc] init];
    [self.mainNav pushViewController:vc animated:YES];
  }
  if ([shortcutItem.type isEqualToString:@"item2"]) {
    Item2ViewController *vc = [[Item2ViewController alloc] init];
    [self.mainNav pushViewController:vc animated:YES];
  }
}

运行效果:

step1

Peek and Pop

3D Touch按压力度可以分为两级,一级力度触发peek,二级力度触发pop

peek相当于预览与按压view相关的view controllerpop相当于跳转至对应的view controller

为view添加3D Touch响应

本文以UIImageView为例,实现图片的预览效果。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
  //  创建ImageView
  self.imageView = [[UIImageView alloc]
      initWithFrame:CGRectMake(self.view.bounds.size.width / 2 - 50, 300, 100,
                               100)];
  self.imageView.image = [UIImage imageNamed:@"junxi3.jpeg"];
  //  非常重要
  self.imageView.userInteractionEnabled = YES;
  [self.view addSubview:self.imageView];
  //  添加3D Touch 响应
  if (self.traitCollection.forceTouchCapability ==
      UIForceTouchCapabilityAvailable) {
    [self registerForPreviewingWithDelegate:self sourceView:self.imageView];
  } else {
    NSLog(@"您的设备不支持3D Touch");
  }

通过UIViewControllerregisterForPreviewingWithDelegate:sourceView:方法添加3D Touch响应。需要遵守UIViewControllerPreviewingDelegate协议,并实现分别对应peekpop的代理方法。

注意,添加3D Touch响应的view,一定要使userInteractionEnabled = YES,否则无法响应。

peek相关代理方法实现

实现代理方法previewingContext:viewControllerForLocation:,在该代理方法中创建并返回待预览的view controller

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
//  peek
- (UIViewController *)previewingContext:
                          (id<UIViewControllerPreviewing>)previewingContext
              viewControllerForLocation:(CGPoint)location {
  //  log信息
  NSLog(@"peek");
  NSLog(@"point %@", NSStringFromCGPoint(location));
  NSLog(@"rect %@", NSStringFromCGRect(previewingContext.sourceRect));
  //  创建待预览view controller
  PreviewViewController *previewVC = [[PreviewViewController alloc] init];
  //  设置大小
  previewVC.preferredContentSize = CGSizeMake(0.0f, 0.0f);
  //  设置内容
  previewVC.image = self.imageView.image;
  //  设置高亮显示区域,其他区域会模糊显示
  previewingContext.sourceRect = self.imageView.frame;
  //  返回待预览view controller
  return previewVC;
}

其中,previewingContext.sourceRect用于设置高亮区域,location为点击手势在view中的位置,preferredContentSize用于设置预览区域大小,为0时系统会设为最佳显示大小。

运行效果:

step2 step3

在PreviewViewController中添加预览状态快捷选项

peek状态下,向上滑动,即可弹出快捷选项。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
- (NSArray<id<UIPreviewActionItem>> *)previewActionItems {
  // setup a list of preview actions
  UIPreviewAction *action1 = [UIPreviewAction
      actionWithTitle:@"Aciton1"
                style:UIPreviewActionStyleDefault
              handler:^(UIPreviewAction *_Nonnull action,
                        UIViewController *_Nonnull previewViewController) {
                NSLog(@"Aciton1");
              }];

  UIPreviewAction *action2 = [UIPreviewAction
      actionWithTitle:@"Aciton2"
                style:UIPreviewActionStyleDefault
              handler:^(UIPreviewAction *_Nonnull action,
                        UIViewController *_Nonnull previewViewController) {
                NSLog(@"Aciton2");
              }];

  UIPreviewAction *action3 = [UIPreviewAction
      actionWithTitle:@"Aciton3"
                style:UIPreviewActionStyleDefault
              handler:^(UIPreviewAction *_Nonnull action,
                        UIViewController *_Nonnull previewViewController) {
                NSLog(@"Aciton3");
              }];

  NSArray *actions = @[ action1, action2, action3 ];
  return actions;
}

运行效果:

step4

pop相关代理方法

实现代理方法previewingContext:commitViewController:,在该代理方法中跳转。

1
2
3
4
5
6
7
8
//  pop
- (void)previewingContext:(id<UIViewControllerPreviewing>)previewingContext
     commitViewController:(UIViewController *)viewControllerToCommit {
  //  log信息
  NSLog(@"pop");
  //  跳转至对应view controller
  [self showViewController:viewControllerToCommit sender:self];
}

运行效果:

step5

3D Touch Force简单运用

touchesMoved:withEvent:方法中,获取touch对象,可以根据force属性值做相应操作。

1
2
3
4
5
- (void)touchesMoved:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event {
  NSArray *arrayTouch = [touches allObjects];
  UITouch *touch = (UITouch *)[arrayTouch lastObject];
  NSLog(@"force = %f", touch.force);
}

参考资料

Adopting 3D Touch on iPhone

iOS9新特性 3DTouch 开发教程全解

Github源码

3DTouchDemo

Comments