iOS 3D Touch

3D Touch功能主要分为以下三个模块:

  • 1、Home Screen Quick Actions

通过主屏幕的应用Icon,我们可以用3D Touch呼出一个菜单,进行快速定位应用功能模块相关功能的开发。

  • 2、peek and pop

这个功能是一套全新的用户交互机制,在使用3D Touch时,ViewController中会有如下三个交互阶段:

3DTouch有两种体现方式,第一种是通过Peek 轻按App icon弹出选项菜单,第二种是在App内的界面上通过Peek 轻按,弹出的预览界面

3、Force Properties

iOS9为我们提供了一个新的交互参数:力度。我们可以检测某一交互的力度值,来做相应的交互处理。例如,我们可以通过力度来控制快进的快慢,音量增加的快慢等。

  1. 轻按app icon弹出选项菜单 代码实现

在app启动时配置application.shortcutItems,注意版本适配

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
    // Override point for customization after application launch.
    
    [self setupShortcutItems:application];
    
    return YES;
}

- (void)setupShortcutItems:(UIApplication *)application {
    
    // 通过Peek 用力按app icon 弹出
#ifdef __IPHONE_9_0
    // 判断该版本xcode的API是否可用,编译时是否需要生成这段代码
    // 创建标签中的icon
    // 自定义图片的icon
    UIApplicationShortcutIcon *icon1 = [UIApplicationShortcutIcon iconWithTemplateImageName:@"fts_search_wechat_icon_46x46_"];
    UIApplicationShortcutIcon *icon2 = [UIApplicationShortcutIcon iconWithTemplateImageName:@"fts_websearch_icon_46x46_"];
    // 使用系统风格的icon
    UIApplicationShortcutIcon *icon3 = [UIApplicationShortcutIcon iconWithType:UIApplicationShortcutIconTypeShare];
    
    UIMutableApplicationShortcutItem *item1 = [[UIMutableApplicationShortcutItem alloc] initWithType:shortcutItemType1Key localizedTitle:@"添加到通讯录" localizedSubtitle:@"点击即可添加到通讯录" icon:icon1 userInfo:nil];
    UIMutableApplicationShortcutItem *item2 = [[UIMutableApplicationShortcutItem alloc] initWithType:shortcutItemType2Key localizedTitle:@"搜索" localizedSubtitle:@"在微信中搜索你想要查找的" icon:icon2 userInfo:nil];
    UIMutableApplicationShortcutItem *item3 = [[UIMutableApplicationShortcutItem alloc] initWithType:shortcutItemType3Key localizedTitle:@"分享" localizedSubtitle:@"分享此app" icon:icon3 userInfo:nil];
    
    application.shortcutItems = @[item1, item2, item3];;
#endif
}

轻按app icon弹出的菜单,点击菜单的item的回调, 通过shortcutItem的type判断不同的item,处理不同的逻辑


#ifdef __IPHONE_9_0
/// 点击app上标签item后,进入时对应事件的处理,
-(void)application:(UIApplication *)application performActionForShortcutItem:(UIApplicationShortcutItem *)shortcutItem completionHandler:(void (^)(BOOL))completionHandler {
    UINavigationController *nav = (UINavigationController *)self.window.rootViewController;
    if([shortcutItem.type isEqualToString:shortcutItemType1Key]){
        NSLog(@"点击了添加到通讯录");
        UIViewController *vc = [[UIViewController alloc] init];
        vc.title = @"通讯录";
        vc.view.backgroundColor = [UIColor yellowColor];
        [nav pushViewController:vc animated:YES];
    }
    if ([shortcutItem.type isEqualToString:shortcutItemType2Key]){
        NSLog(@"点击了搜索");
        UIViewController *vc = [[UIViewController alloc] init];
        vc.title = @"搜索";
        vc.view.backgroundColor = [UIColor redColor];
        [nav pushViewController:vc animated:YES];
    }
    
    if ([shortcutItem.type isEqualToString:shortcutItemType3Key]) {
        NSLog(@"点击了分享");
        UIViewController *vc = [[UIViewController alloc] init];
        vc.title = @"分享";
        vc.view.backgroundColor = [UIColor blueColor];
        [nav pushViewController:vc animated:YES];
    }
}
#endif

2.App内界面上通过Peek 用户按弹出的预览界面
首先在需要弹出预览的控制器中检测设备是否支持3d touch 功能, 并注册预览代理,实现UIViewControllerPreviewingDelegate方法

@implementation ViewController
- (void)viewWillAppear:(BOOL)animated {
    [super viewWillAppear:animated];
    
    /// 检测是否有3d touch 功能
    if ([self respondsToSelector:@selector(traitCollection)]) {
        if ([self.traitCollection respondsToSelector:@selector(forceTouchCapability)]) {
            if (self.traitCollection.forceTouchCapability == UIForceTouchCapabilityAvailable) {
                // 支持3D Touch
                if ([self respondsToSelector:@selector(registerForPreviewingWithDelegate:sourceView:)]) {
                    [self registerForPreviewingWithDelegate:self sourceView:self.view];
                }
            } else {
                // 不支持3D Touch
            }
        }
    }
}

#pragma mark - UIViewControllerPreviewingDelegate

#ifdef __IPHONE_9_0

// 弹出预览页面
- (nullable UIViewController *)previewingContext:(id )previewingContext viewControllerForLocation:(CGPoint)location NS_AVAILABLE_IOS(9_0) {
    
    // previewingContext.sourceView: 触发Peek & Pop操作的视图
    // previewingContext.sourceRect: 设置触发操作的视图的不被虚化的区域
    
    MyViewController *myVc = [MyViewController new];
    // 预览区域大小(可不设置)
    myVc.preferredContentSize = CGSizeMake(0, 320);
    return myVc;
    
}



// 在弹出页面的基础上,再继续用力按下去,就会push预览界面了。(pop功能)
- (void)previewingContext:(id )previewingContext commitViewController:(UIViewController *)viewControllerToCommit NS_AVAILABLE_IOS(9_0) {
    
    [self showViewController:viewControllerToCommit sender:self];
}

#endif

@end

如果想要在3D Touch 触发显示预览界面的情况下,设置向上滑动视图,下面出现的菜单,需要在预览视图的控制器中重写previewActionItems,添加UIPreviewAction(弹出的每个按钮)

@implementation MyViewController
// 实现这个方法之后, 3D Touch触发的情况下,向上滑动视图,下面会出现菜单
// 这个方法就是定义向上滑动的菜单的
#ifdef __IPHONE_9_0
- (NSArray> *)previewActionItems NS_AVAILABLE_IOS(9_0) {
    return @[
             [UIPreviewAction actionWithTitle:@"iTem1" style:UIPreviewActionStyleDefault handler:^(UIPreviewAction * _Nonnull action, UIViewController * _Nonnull previewViewController) {
                 NSLog(@"点击了iTem1,%@", action);
                 
             }],
             [UIPreviewAction actionWithTitle:@"iTem2" style:UIPreviewActionStyleDefault handler:^(UIPreviewAction * _Nonnull action, UIViewController * _Nonnull previewViewController) {
                 NSLog(@"点击了iTem2,%@", action);
             }],
             [UIPreviewAction actionWithTitle:@"iTem3" style:UIPreviewActionStyleDefault handler:^(UIPreviewAction * _Nonnull action, UIViewController * _Nonnull previewViewController) {
                 NSLog(@"点击了iTem3,%@", action);
             }]
             ];
}
#endif

@end

3.添加widget

iOS 3D Touch_第1张图片
WechatIMG11.jpeg
  • 1.如何为现有的工程添加widget;
    在现有的项目的中创建widget
    Xcode菜单 -> File -> New -> Target.. -> 选择Today Extension

新建一个target


iOS 3D Touch_第2张图片
屏幕快照 2017-04-29 下午10.56.12.png

选择Today Extension


iOS 3D Touch_第3张图片
Snip20170429_1.png

为你的target名称后创建完成,会出现5个文件, 下面也是添加Today Extension之后的项目

iOS 3D Touch_第4张图片
Snip20170429_3.png

如果你想使用存代码,不用storyboard搭建UI ,可以在Widget这个target中删除MainInterface.storyboard,并在info.plist中删除NSExtensionMainStoryboard,并添加NSExtensionPrincipalClass,设置其value为TodayViewController


Snip20170429_4.png
  • 2如何写UI界面
    在系统生成的TodayViewController中构建UI界面
- (void)viewDidLoad {
    [super viewDidLoad];
    // 设置widget展示的视图大小
    self.preferredContentSize = CGSizeMake([UIScreen mainScreen].bounds.size.width, 100);
}
  • 3.点击widge处调用app
    点击Widget布局任何区域都能唤起主应用程序,常用的方式在整个TodayViewController的View增加Tap事件
    因为extension和app是两个完全独立的进程,所以它们之间不能直接通信(不能像应用内部点击按钮,跳转到指定页面)。为了实现widget调起app,这里通过openURL的方式来启动app。
- (void)viewDidLoad {
    [super viewDidLoad];
    // Do any additional setup after loading the view from its nib.
    
    // 设置widget展示的视图大小
    self.preferredContentSize = CGSizeMake([UIScreen mainScreen].bounds.size.width, 100);
    
    // 如你所看当用户拉开Widget时,因为Widget是依赖于应用程序在分发时是跟应用程序一块打包的,希望点击Widget布局任何区域都能唤起主应用程序,常用的方式在整个View增加Tap事件订阅处理
    [self.view addGestureRecognizer:[[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(openApp:)]];
    
    // 但这种方式会额外产生一个问题,如果Widget空白区域没有任何UI元素则无法触发该事件,那这里有一个小技巧可以解决改问题,可以整个Widget增加一个透明的ImageView:
    // 创建一个透明的ImageView作为widge整个背景
    UIImageView *bgImageView = [UIImageView new];
    bgImageView.userInteractionEnabled = YES;
    bgImageView.alpha = 0.01;
    bgImageView.backgroundColor = [UIColor grayColor];
    [self.view addSubview:bgImageView];
    bgImageView.frame = self.view.bounds;
    
}

// 点击整个widget区域的事件
- (void)openApp:(UITapGestureRecognizer *)tap {
    [self.extensionContext openURL:[NSURL URLWithString:@"TodayDemo://action=jumpToHomePage"]
                 completionHandler:^(BOOL success) {
                NSLog(@"打开%@", success ? @"成功" : @"失败");
                 }];

}


如果要完成widget调用app,需要在info.plist中配置URL Types


iOS 3D Touch_第5张图片
屏幕快照 2017-04-30 上午9.10.40.png

app需要处理接收跳转,这个在AppDelegate的代理方法中设置

// 接收来自TodayViewController的跳转
- (BOOL)application:(UIApplication *)app openURL:(NSURL *)url options:(NSDictionary *)options {
    
    NSString *prefix = @"TodayDemo://";
    if ([[url absoluteString] rangeOfString:prefix].location != NSNotFound) {
        NSString *func = [[url absoluteString] substringFromIndex:prefix.length];
        if ([func isEqualToString:@"jumpToHomePage"]) {
            
        }
        
        else if([func isEqualToString:@"jumpToOtherPage"]) {
            
        }
    }
    return YES;
}
  • 4.如何与host app共享数据。

Demo

在iOS10换出菜单都有分享这个事件,这个事件是系统自动添加的,并且apple在调试的时候不会出现这个分享的事件(不知道这个调试的时候好坑人啊,一直在纠结怎么弄不出来那个分享的事件)
在打包ipa时,可以发现有这个 分享Beta版反馈 的事件,appstore 的包出现 分享“app名称”

# define __IPHONE_9_2 90200
这些宏的作用是判断该版本的xcode是否具有这个宏所定义的系统的API,在xcode中有这个宏就代表有这个宏所定义的系统的API。

#define kCurrentSystemVersion ([[[UIDevice currentDevice] systemVersion] floatValue])
通常这个宏是用来区分手机不同版本的系统应该使用什么版本的API。

你可能感兴趣的:(iOS 3D Touch)