美文网首页
iOS 3D Touch

iOS 3D Touch

作者: 字节码 | 来源:发表于2017-04-29 19:26 被阅读70次

    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 <UIViewControllerPreviewing>)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 <UIViewControllerPreviewing>)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<id<UIPreviewActionItem>> *)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

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

    新建一个target


    屏幕快照 2017-04-29 下午10.56.12.png

    选择Today Extension


    Snip20170429_1.png

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

    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


    屏幕快照 2017-04-30 上午9.10.40.png

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

    // 接收来自TodayViewController的跳转
    - (BOOL)application:(UIApplication *)app openURL:(NSURL *)url options:(NSDictionary<UIApplicationOpenURLOptionsKey,id> *)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

          本文链接:https://www.haomeiwen.com/subject/ybozzttx.html