3D Touch 简单应用

随着iPhone 6s 和 iPhone 6s Plus 的发布,苹果开始添加了一种全新的触控方式——3D Touch。最近几天简单地研究了一下,跟你们分享一下个人一些经验。html

##UIApplicationShortcutItems

当你重按应用的图标时,会弹出相似这样的小菜单(以微信为例): ios

ShortcutItems

添加这样的快捷菜单主要有 静态动态 两种方法: ####静态方法 参看 UIApplicationShortcutItems-苹果官方文档git

ShortcutItems 变量说明

能够看到 UIApplicationShortcutItemTitleUIApplicationShortcutItemType 这两个变量是必须的。github

咱们在项目的 info.plist 文件中添加以下信息: 数组

静态添加 `ShortcutItems`

运行结果: 微信

####动态方法 动态方法是在项目中添加代码:app

UIApplicationShortcutItem *item1 = [[UIApplicationShortcutItem alloc] initWithType:@"one" localizedTitle:@"Title One" localizedSubtitle:@"Sub one" icon:[UIApplicationShortcutIcon iconWithType:UIApplicationShortcutIconTypePlay] userInfo:nil];
UIApplicationShortcutItem *item2 = [[UIApplicationShortcutItem alloc] initWithType:@"two" localizedTitle:@"Title Two" localizedSubtitle:@"Sub two" icon:[UIApplicationShortcutIcon iconWithType:UIApplicationShortcutIconTypeHome] userInfo:nil];

[UIApplication sharedApplication].shortcutItems = @[item1, item2];
复制代码

当该段代码在程序中被执行过一次后才会被添加到主屏幕的 ShortcutItems 菜单中。 运行结果:dom

注意: ShortcutItems 会优先加载静态方法添加的,而后加载动态方法添加的,而且同时只能拥有最多4个ShortcutItems。测试

####选择 ShortcutItem 后的回调 在 AppDelegate 根据 shortcutItem.type 判断回调方法:ui

- (void)application:(UIApplication *)application performActionForShortcutItem:(UIApplicationShortcutItem *)shortcutItem completionHandler:(void (^)(BOOL))completionHandler {

    if ([shortcutItem.type isEqualToString:@"one"]) {
        NSLog(@"Choose One");
        MyViewController *vc = [[MyViewController alloc] init];
        vc.title = @"One";
        vc.view.backgroundColor = [UIColor whiteColor];
        [self.window.rootViewController showViewController:vc sender:nil];
    } else if ([shortcutItem.type isEqualToString:@"two"]) {
        NSLog(@"Choose Two");
        MyViewController *vc = [[MyViewController alloc] init];
        vc.title = @"Two";
        vc.view.backgroundColor = [UIColor orangeColor];
        [self.window.rootViewController showViewController:vc sender:nil];
    }    
}
复制代码

按压力度感应


在9.0后 UITouch 新增这样两个属性:

9.0新增touch属性

咱们建立一个继承于 UIView 的自定义View,这里咱们首先要判断一下设备是否支持3D Touch:

- (BOOL)check3DTouch {
    if (self.traitCollection.forceTouchCapability == UIForceTouchCapabilityAvailable) {
        return YES;
    } else {
        return NO;
    }
}
复制代码

而后在 touchesMoved 中调用方法:

- (void)touchesMoved:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event {
    
    if ([self check3DTouch]) {
        UITouch *touch = [touches anyObject];
        self.backgroundColor = [UIColor colorWithRed:touch.force / touch.maximumPossibleForce  green:0.0f blue:0.0f alpha:1.0f];
    } else {
        NSLog(@"CAN NOT USE 3D TOUCH!");
    }
}
复制代码

这样咱们我建立了一个能够根据按压力度改变颜色的View。

Peek & Pop


####Peek和Pop: Peek是指重按一下后出现的预览,Pop是在Peek后进一步按压后进入预览的视图控制器。 首先遵循代理 <UIViewControllerPreviewingDelegate> 而后监测设备是否支持3D Touch,若支持则对须要响应Peek操做的视图进行注册:

- (void)check3DTouch {
    if (self.traitCollection.forceTouchCapability == UIForceTouchCapabilityAvailable) {
        [self registerForPreviewingWithDelegate:self sourceView:_label];
    }
}
复制代码

Peek的代理方法

- (UIViewController *)previewingContext:(id<UIViewControllerPreviewing>)previewingContext viewControllerForLocation:(CGPoint)location {
      MyViewController *vc = [[MyViewController alloc] init];
      vc.title = @"Hello";
      vc.view.backgroundColor = [UIColor cyanColor];
      return vc;
}
复制代码

其实就是返回一个视图控制器实例,可是看网上说这个方法会被屡次调用,我实际测试有时会调用屡次,有时只调用一次,仍是不太清楚具体调用状况,有知道的朋友欢迎交流一下。为了保险起见,仍是建议写成下面的形式:

- (UIViewController *)previewingContext:(id<UIViewControllerPreviewing>)previewingContext viewControllerForLocation:(CGPoint)location {
    if ([self.presentedViewController isKindOfClass:[MyViewController class]]) {
        return nil;
    } else {
        MyViewController *vc = [[MyViewController alloc] init];
        vc.title = @"Hello";
        vc.view.backgroundColor = [UIColor cyanColor];
        return vc;
    }
}
复制代码

至于Pop的方法就更简单了,直接调用下面的方法: Pop的代理方法

- (void)previewingContext:(id<UIViewControllerPreviewing>)previewingContext commitViewController:(UIViewController *)viewControllerToCommit {
    [self showViewController:viewControllerToCommit sender:self];
}
复制代码

PreviewAction Items

有时在进入Peek但未Pop的时候,咱们能够向上滑动选 PreviewAction Items

PreviewAction Items

PreviewAction Items 是在被预览的viewController下面添加下面方法实现的:

- (NSArray<id<UIPreviewActionItem>> *)previewActionItems {
    UIPreviewAction *action1 = [UIPreviewAction actionWithTitle:@"Default" style:UIPreviewActionStyleDefault handler:^(UIPreviewAction * _Nonnull action, UIViewController * _Nonnull previewViewController) {
        
    }];
    UIPreviewAction *action2 = [UIPreviewAction actionWithTitle:@"Selected" style:UIPreviewActionStyleSelected handler:^(UIPreviewAction * _Nonnull action, UIViewController * _Nonnull previewViewController) {
        
    }];
    UIPreviewAction *action3 = [UIPreviewAction actionWithTitle:@"Destructive" style:UIPreviewActionStyleDestructive handler:^(UIPreviewAction * _Nonnull action, UIViewController * _Nonnull previewViewController) {
        
    }];
    NSArray *actions = @[action1, action2, action3];
    
    UIPreviewActionGroup *group = [UIPreviewActionGroup actionGroupWithTitle:@"Actions Group" style:UIPreviewActionStyleDefault actions:actions];
    
    UIPreviewAction *action4 = [UIPreviewAction actionWithTitle:@"Single Action" style:UIPreviewActionStyleDefault handler:^(UIPreviewAction * _Nonnull action, UIViewController * _Nonnull previewViewController) {
        
    }];

    NSArray *array = @[group, action4];

    return array;
}
复制代码

经过返回 UIPreviewActionUIPreviewActionGroup 组成的数组实现。

一个viewController下注册多个视图控件

前面说到若是要让视图控件响应Peek操做须要对其进行注册,可是若是一个viewController中有多个控件须要响应Peek而且可能不知道什么时候会出现的时候(譬如添加了一个tableView后,须要每个单独的cell独立响应一个Peek操做),是不可能一个一个注册的,这个时候咱们能够直接将- (void)check3DTouch 中的代码改为:

- (void)check3DTouch {
    if (self.traitCollection.forceTouchCapability == UIForceTouchCapabilityAvailable) {
        [self registerForPreviewingWithDelegate:self sourceView:self.view];
    }
}
复制代码

咱们直接注册整个view,根据peek代理方法中的属性location 判断响应的UI控件

- (UIViewController *)previewingContext:(id<UIViewControllerPreviewing>)previewingContext viewControllerForLocation:(CGPoint)location {

    if (CGRectContainsPoint(_tableView.frame, location)) {
        if ([self.presentedViewController isKindOfClass:[DisplayViewController class]]) {
            return nil;
        } else {
            location = [self.view convertPoint:location toView:_tableView];
            NSIndexPath *indexPath = [_tableView indexPathForRowAtPoint:location];
            NSLog(@"%@", indexPath);
            DisplayViewController *displayVC = [[DisplayViewController alloc] init];
            displayVC.title = [_tableView cellForRowAtIndexPath:indexPath].textLabel.text;
            displayVC.view.backgroundColor = [UIColor colorWithRed:arc4random() % 256 / 256.0
                                                             green:arc4random() % 256 / 256.0
                                                              blue:arc4random() % 256 / 256.0
                                                             alpha:1.0];
            
            // peek预览窗口大小
            displayVC.preferredContentSize = CGSizeMake(0.0, 100 * indexPath.row);
            
            // 进入peek前不被虚化的rect
            previewingContext.sourceRect = [self.view convertRect:[_tableView cellForRowAtIndexPath:indexPath].frame fromView:_tableView];
            
            return displayVC;
        }
    }
    
    
    if ([self.presentedViewController isKindOfClass:[MyViewController class]]) {
        return nil;
    } else {
        if (CGRectContainsPoint(_label.frame, location)) {
            MyViewController *vc = [[MyViewController alloc] init];
            vc.title = @"Hello";
            vc.view.backgroundColor = [UIColor cyanColor];
            NSLog(@"New ViewController.");
            return vc;
        }
    }
    
    return nil;
}
复制代码

3D Touch 小应用 —— 压力感应画板


这段是引用了 crazypoo/TouchNewAPI 的代码

- (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event {
    UITouch *touch = [touches anyObject];
    _touchPoint = [touch locationInView:_drawBoard];
}

- (void)touchesMoved:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event {
    UITouch *touch = [touches anyObject];
    CGPoint currentPoint = [touch locationInView:_drawBoard];
    
    UIGraphicsBeginImageContext(_drawBoard.frame.size);
    [_drawBoard.image drawInRect:_drawBoard.frame];
    CGContextSetLineCap(UIGraphicsGetCurrentContext(), kCGLineCapRound);
    
    float lineWidth = 10.0f;
    if (self.traitCollection.forceTouchCapability == UIForceTouchCapabilityAvailable) {
        lineWidth *= touch.force;
    }
    
    CGContextSetLineWidth(UIGraphicsGetCurrentContext(), lineWidth);
    CGContextSetRGBStrokeColor(UIGraphicsGetCurrentContext(), 0.0, 0.0, 0.0, 1.0);
    CGContextMoveToPoint(UIGraphicsGetCurrentContext(), _touchPoint.x, _touchPoint.y);
    CGContextAddLineToPoint(UIGraphicsGetCurrentContext(), currentPoint.x, currentPoint.y);
    CGContextStrokePath(UIGraphicsGetCurrentContext());
    _drawBoard.image = UIGraphicsGetImageFromCurrentImageContext();
    UIGraphicsEndImageContext();
    
    _touchPoint = currentPoint;
}
复制代码

以上是个人一点浅薄的心得,本文中全部代码都已经上传至 kisekied/3DTouchDemo 欢迎你们交流讨论。

相关文章
相关标签/搜索