iOS9 3D Touch

iOS9出来了一个新的接口,3Dtouch,而且屏幕必须支持3dtouch功能才能运用到这个模块,也就是苹果新的手机吧,6s以上系列的。

这个貌似不能用模拟器开发,但是网上找了一篇能用模拟器测试的,是一个第三方的库,没用,贴出来吧:

http://my.oschina.net/u/2340880/blog/511509

3Dtouch接口提供了四种用户操作行为:

1,主屏幕(HOME)快速启动,也就是用力摁,快速action。

2,应用启动之后,用力摁某个内容,会进行相应的操作。

3,webview用力摁链接,也就是URL,会出现URL地址内容的预览效果。

4,用户自定义的3dtouch的操作。

一,home界面的快速启动页面,分两种,第一种是静态的快速启动,也就是写死的,写死在plist文件里边的,不能改变的。第二种是用代码写的,在rootViewController或者appdelegate里边写的。

1>,静态quick action。

首先检测当前设备是否支持3Dtouch或者用户是否在设置里边打开3Dtouch。

-(void)viewWillAppear:(BOOL)animated
{
[super viewWillAppear:animated];
 
if(self.traitCollection.forceTouchCapability == UIForceTouchCapabilityUnavailable){
 
NSLog(@"提示用户去打开3DTouch");
 
}
}
//self.traitCollection.forceTouchCapability的值检测是否打开,有三个:
 
/*
typedef NS_ENUM(NSInteger, UIForceTouchCapability) {
UIForceTouchCapabilityUnknown = 0,未知
UIForceTouchCapabilityUnavailable = 1,未打开
UIForceTouchCapabilityAvailable = 2打开
};
*/

如果用户在操作当前APP的时候,修改了设置,调用viewcontroller的生命周期方法,重新检测,重新提示:

//To be overridden as needed to provide custom behavior when the environment's traits change.
//apple 的描述,特意改变某个设置之后运行的方法
-(void)traitCollectionDidChange:(UITraitCollection *)previousTraitCollection
{
if(self.traitCollection.forceTouchCapability == UIForceTouchCapabilityUnavailable){
 
NSLog(@"提示用户去打开3DTouch");
 
}
}

3Dtouch配置,配置plist文件:

官方是这么写的,在app的info.plist文件里边加一个键,这个键是一个数组:UIApplicationShortcutItems,官网这么描述的:

UIApplicationShortcutItems的键值对有:

首先UIApplicationShortcutItems是一个数组,每个数组保存的对象是一个字典。每一个字典里边官方给出的description:

软件翻译的,估计不怎么准备,不过比人翻译的好多了:

UIApplicationShortcutItemType和UIApplicationShortcutItemTitle是必须的,其他都是可选的,UIApplicationShortcutItemType指定了当前action的类型,以便不同的action在处理的时候冲突,UIApplicationShortcutItemTitle指定了当前action的title。

其他的都是一些图标,userInfo是一些传递的值,等。subtitle是二级标题,我的plist文件:

    <key>UIApplicationShortcutItems</key>
    <array>
        <dict>
            <key>UIApplicationShortcutItemIconFile</key>
            <string>btn-xihuan-n</string>
            <key>UIApplicationShortcutItemIconType</key>
            <string>UIApplicationShortcutIconTypeUpdate</string>
            <key>UIApplicationShortcutItemSubtitle</key>
            <string>醉生梦死</string>
            <key>UIApplicationShortcutItemTitle</key>
            <string>Ashes of time</string>
            <key>UIApplicationShortcutItemType</key>
            <string>com.5.Touch3DDemo.StaticFirst</string>
            <key>UIApplicationShortcutItemUserInfo</key>
            <dict>
                <key>currentType</key>
                <string>testType</string>
                <key>currentValue</key>
                <string>testValye</string>
            </dict>
        </dict>
    </array>

2>,动态快速启动(Dynamic quick actions).

用户在app的启动页面,可以是delegate里边,也可以是rootviewcontroller里边,用UIApplicationShortcutItem,或者UIMutableApplicationShortcutItem类创建快速启动,目前还不知道这两个类的区别,可能是为了扩展吧。然后在UIApplication中设置shortcutItems。里边用到了UIApplicationShortcutIcon类,也就是图标设置类。

原文:

Dynamic quick actions are available to the user after first launch. Define Home screen dynamic quick actions with the UIApplicationShortcutItem, UIMutableApplicationShortcutItem, and UIApplicationShortcutIcon classes. Add dynamic quick actions to your app’s shared UIApplication object using the shortcutItems property.

创建:

- (void)viewDidLoad {
    [super viewDidLoad];
    
    //创建
    //动态的quick action,icon可以是系统的,也可以是自己项目中得图片
    UIApplicationShortcutItem * item = [[UIApplicationShortcutItem alloc]initWithType:@"com.5.Touch3DDemo.AutoSecond" localizedTitle:@"3DtouchTest" localizedSubtitle:@"AutoSecond" icon:[UIApplicationShortcutIcon iconWithType:0] userInfo:nil];
    //[UIApplication sharedApplication].shortcutItems = @[item];
    
    UIMutableApplicationShortcutItem *item1 = [[UIMutableApplicationShortcutItem alloc]initWithType:@"this type" localizedTitle:@"second type"];
    
    UIApplicationShortcutIcon *icon = [UIApplicationShortcutIcon iconWithTemplateImageName:@"btn-xihuan-n"];
    
    UIMutableApplicationShortcutItem *item2 = [[UIMutableApplicationShortcutItem alloc]initWithType:@"this second type" localizedTitle:@"my menu" localizedSubtitle:@"my subTitle" icon:icon userInfo:@{@"info1":@"value1"}];
    //添加
    [UIApplication sharedApplication].shortcutItems = @[item,item1,item2];
    
    // Do any additional setup after loading the view, typically from a nib.
}

获取快速启动的类型或者userInfo,进行不同的操作:

在appdelegate的委托方法ios9新加了一个一个方法,就是获取quick action的委托,获取item的各种信息,以便进行操作。

此方法向主屏幕快速行动为您的应用程序的用户的选择作出反应;叫完成处理程序.

官方解释:https://developer.apple.com/library/prerelease/ios/documentation/UIKit/Reference/UIApplicationDelegate_Protocol/index.html#//apple_ref/occ/intfm/UIApplicationDelegate/application:performActionForShortcutItem:completionHandler:

如果应用在后台运行,用快速启动打开了应用,那么则会调用appdelegate的委托方法:

#pragma mark - shortItem
- (void)application:(UIApplication *)application performActionForShortcutItem:(nonnull UIApplicationShortcutItem *)shortcutItem completionHandler:(nonnull void (^)(BOOL))completionHandler
{
    NSLog(@"userInfo  - - -   %@",shortcutItem.userInfo);
    if(shortcutItem.type){
        //other action
    }
    if(completionHandler){
        completionHandler(YES);
    }
}

如果用户已经推出后台,要重新打开应用,则需要在didFinishLaunchingWithOptions或者willFinishLaunchingWithOptions方法中获取快速启动item,然后通过判断type,做相应的操作:

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
    // Override point for customization after application launch.
    
    
    UIApplicationShortcutItem *item = [launchOptions objectForKey:UIApplicationLaunchOptionsShortcutItemKey];
    
    if(item.type == [NSObject new]){
    
        //other action
        
    }
    
    return YES;
}
//写在这个里边也行,看实际情况了
-(BOOL)application:(UIApplication *)application willFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
    return YES;
}

给个效果吧:

二,当前控制器添加touch事件。

官方:https://developer.apple.com/library/prerelease/ios/documentation/UserExperience/Conceptual/Adopting3DTouchOniPhone/3DTouchAPIs.html#//apple_ref/doc/uid/TP40016543-CH4-SW1

ios9之后给controller添加了一个属性,presentedViewController,这个是属性就是当用户触发touch事件之后present的一个controller。其实controller中的touch事件是给view添加的。

这个操作主要是用户触发touch事件之后,可以预览某个详情,例如现在的微信,用力摁cell,会出现聊天详情的一个预览。

touch主要操作是1,添加一个预览的controller,2,添加对这个touch事件的操作,官方说的也就是peek。

控制器增加了UIPreviewAction and UIPreviewActionGroup classes ,还有The new UIPreviewActionItem protocol ,协议是当前peek的属性,也就是previewActionItems数组,实现方法。首先在要peek的controller中注册peek事件:

- (void)viewDidLoad {
    [super viewDidLoad];
    //注册事件,用于touch的view是当前的self.view
    [self registerForPreviewingWithDelegate:(id)self sourceView:self.view];
    // Do any additional setup after loading the view, typically from a nib.
}

获取peek事件后peek下一个controller。实现UIViewControllerPreviewingDelegate的协议,这个协议可以不再controller中的.h里边遵循,貌似是apple给父类添加了。

连个代理方法,轻轻用力的时候和力度大的时候,调用不同的代理。用力压的时候则直接显示要peek的controller。用力压属于模态,在第二个出来的controller中可以添加dismiss。

//轻压的时候触发的方法
- (UIViewController *)previewingContext:(id<UIViewControllerPreviewing>)context viewControllerForLocation:(CGPoint)point {
    //判断当前controller的presentedViewController是不是已经存在,如果存在,那么不进行操作
    if ([self.presentedViewController isKindOfClass:[CustomPageViewController class]]){
        return nil;
    }
    else {
        //创建当前controller的presentedViewController
        CustomPageViewController *peekViewController = [[CustomPageViewController alloc] init];
        //传值
        peekViewController.value = @"this value";
        
        return peekViewController;
    }
}
//用力压的时候触发的方法
-(void)previewingContext:(id<UIViewControllerPreviewing>)previewingContext commitViewController:(UIViewController *)viewControllerToCommit
{
    CustomPageViewController *peekViewController = [[CustomPageViewController alloc] init];
    
    //传值
    peekViewController.value = @"this value";
    
    [self showViewController:peekViewController sender:self];
}

CustomPageViewController是新创建的controller,继承于UIPageViewController,peek在当前controller上的controller。

在CustomPageViewController中可以看到刚刚将传过来的string显示在label上边:

- (void)viewDidLoad {
    [super viewDidLoad];
    
    self.view.backgroundColor = [UIColor orangeColor];
    
    UILabel *lb = [[UILabel alloc]initWithFrame:CGRectMake(0, 0, 200, 200)];
    
    lb.backgroundColor = [UIColor whiteColor];
    
    if(_value) lb.text = _value;
    
    lb.center = self.view.center;
    
    [self.view addSubview:lb];
    
    // Do any additional setup after loading the view.
}
 
/*官方文档,意思是可以直接调用presentViewController:animated:completion这个方法
For example, to present the commit view controller’s view in a navigation controller, call the navigation controller’s showViewController:sender: method; to present the view modally, you could call the presentViewController:animated:completion: method. 
*/
-(void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event
{
    [self dismissViewControllerAnimated:YES completion:nil];
}

然后加peek事件,也就是类似actionsheet一样的东西。

用到了UIPreviewActionGroup,和UIPreviewAction。

UIPreviewActionGroup和UIPreviewAction都是遵循UIPreviewActionItem协议的,所以返回可以是UIPreviewActionGroup的数组,也可以是UIPreviewAction的数组,UIPreviewAction是组,也就是队列action。

controller多了一个previewActionItems的属性,重写previewActionItems的setter方法在controller中:

1>,选择action直接操作,返回数组:

-(NSArray<id<UIPreviewActionItem>> *)previewActionItems
{
    UIPreviewAction *action1 = [UIPreviewAction actionWithTitle:@"1" style:(UIPreviewActionStyleDefault) handler:^(UIPreviewAction * _Nonnull action, UIViewController * _Nonnull previewViewController) {
        
        NSLog(@"2 action");
        
    }];
    
    UIPreviewAction *action2 = [UIPreviewAction actionWithTitle:@"2" style:(UIPreviewActionStyleDefault) handler:^(UIPreviewAction * _Nonnull action, UIViewController * _Nonnull previewViewController) {
        
        NSLog(@"3 action");
        
    }];
    
    UIPreviewAction *action3 = [UIPreviewAction actionWithTitle:@"3" style:(UIPreviewActionStyleDefault) handler:^(UIPreviewAction * _Nonnull action, UIViewController * _Nonnull previewViewController) {
        
        NSLog(@"4 action");
        
    }];
    
    return @[action1,action2,action3];
    
}

2>,返回分组,通过点击每个组,可以触发另外一个另外一个组,然后action,如果有更多的操作则推荐这个使用,不然不用。

- (NSArray<id<UIPreviewActionItem>> *)previewActionItems {
    
    // 生成UIPreviewAction
    UIPreviewAction *action1 = [UIPreviewAction actionWithTitle:@"1" style:UIPreviewActionStyleDefault handler:^(UIPreviewAction * _Nonnull action, UIViewController * _Nonnull previewViewController) {
        NSLog(@"choosed 1");
    }];
    
    UIPreviewAction *action2 = [UIPreviewAction actionWithTitle:@"2" style:UIPreviewActionStyleDestructive handler:^(UIPreviewAction * _Nonnull action, UIViewController * _Nonnull previewViewController) {
        NSLog(@"choosed 2");
    }];
    
    UIPreviewAction *action3 = [UIPreviewAction actionWithTitle:@"3" style:UIPreviewActionStyleSelected handler:^(UIPreviewAction * _Nonnull action, UIViewController * _Nonnull previewViewController) {
        NSLog(@"choosed 3");
    }];
    
    UIPreviewAction *tap1 = [UIPreviewAction actionWithTitle:@"selected 1" style:UIPreviewActionStyleDefault handler:^(UIPreviewAction * _Nonnull action, UIViewController * _Nonnull previewViewController) {
        NSLog(@"group2 selected 1");
    }];
    
    UIPreviewAction *tap2 = [UIPreviewAction actionWithTitle:@"selected 2" style:UIPreviewActionStyleDestructive handler:^(UIPreviewAction * _Nonnull action, UIViewController * _Nonnull previewViewController) {
        NSLog(@"group2 selected 2");
    }];
    
    UIPreviewAction *tap3 = [UIPreviewAction actionWithTitle:@"selected 3" style:UIPreviewActionStyleSelected handler:^(UIPreviewAction * _Nonnull action, UIViewController * _Nonnull previewViewController) {
        NSLog(@"group2 selected 3");
    }];
    
    //添加到到UIPreviewActionGroup中
    NSArray *actions = @[action1, action2, action3];
    NSArray *taps = @[tap1, tap2, tap3];
    UIPreviewActionGroup *group1 = [UIPreviewActionGroup actionGroupWithTitle:@"1 Group" style:UIPreviewActionStyleDefault actions:actions];
    UIPreviewActionGroup *group2 = [UIPreviewActionGroup actionGroupWithTitle:@"2 Group" style:UIPreviewActionStyleDefault actions:taps];
    NSArray *group = @[group1,group2];
    
    return group;
}

handler应该能看出来是点击item之后的action。

UIPreviewActionStyleDefault是UIPreviewAction的模式,有三种,第一种默认,第二个是选中,第三个红色,也可以理解成谨慎操作。

typedef NS_ENUM(NSInteger,UIPreviewActionStyle) {
    UIPreviewActionStyleDefault=0,
    UIPreviewActionStyleSelected,
    UIPreviewActionStyleDestructive,
} NS_ENUM_AVAILABLE_IOS(9_0);

效果:

3,webView touchURL的时候,则出现预览,重摁则打开safari,Peek和Pop会通过Safari Services framewrok中的SFSafariViewController类自动侦测链接和数据。

开启属性

   _web = [[UIWebView alloc]initWithFrame:self.view.frame];
    
    _web.allowsLinkPreview = YES;
    
    [self.view addSubview:_web];
    
    [_web loadRequest:[NSURLRequest requestWithURL:[NSURL URLWithString:@"http://www.iashes.com/"]]];

效果:

demo:http://pan.baidu.com/s/1sj5nBIH 

参考:

 https://developer.apple.com/library/prerelease/ios/documentation/UserExperience/Conceptual/Adopting3DTouchOniPhone/index.html#//apple_ref/doc/uid/TP40016543-CH1-SW1  http://git.devzeng.com/blog/ios9-3d-touch.html

Leave a Reply

Required fields are marked *