标签:
iOS9提供了四类API( Home Screen Quick Action
、 UIKit Peek & Pop
、 WebView Peek & Pop
和 UITouch Force Properties
)用于操作3D Touch。不过无论使用哪一种API,首先需要做的事情是检查3D Touch是否可用。
在iOS9中提供如下的接口用于检查设备是否支持3D Touch:
@property(nonatomic, readonly) UIForceTouchCapability forceTouchCapability;
其中 UIForceTouchCapability
是一个枚举类型,具体的描述情况如下:
这3个枚举值就是我们来判断设备是否开启3D Touch功能,可以在UIViewController生命周期的viewWillAppear中做如下判断:
if (self.traitCollection.forceTouchCapability == UIForceTouchCapabilityAvailable) { //do something }
当然在生命周期内,如果用户有意修改了设备的3D Touch功能,我们还有一个地方来重新检测:
- (void)traitCollectionDidChange:(UITraitCollection *)previousTraitCollection { //do something }
创建Quick Action有两种方式:静态和动态
①以静态方式创建
静态创建的方式是在Info.plist文件中进行声明的
<key>UIApplicationShortcutItems</key> <array> <dict> <key>UIApplicationShortcutItemIconType</key> <string>UIApplicationShortcutIconTypeShare</string> <key>UIApplicationShortcutItemTitle</key> <string>分享</string> <key>UIApplicationShortcutItemType</key> <string>UITouchText.share</string> <key>UIApplicationShortcutItemUserInfo</key> <dict> <key>key1</key> <string>value1</string> </dict> </dict> <dict> <key>UIApplicationShortcutItemType</key> <string>com.devzeng.about</string> <key>UIApplicationShortcutItemTitle</key> <string>关于我们</string> <key>UIApplicationShortcutItemSubtitle</key> <string>这是关于我们</string> <key>UIApplicationShortcutItemIconFile</key> <string>icon_about.png</string> <key>UIApplicationShortcutItemUserInfo</key> <dict> <key>scheme</key> <string>devzeng://about</string> </dict> </dict> </array>
②以动态方式创建
动态创建是在程序初始化的时候用代码动态添加。 UIApplication
对象多了一个支持快捷方式的数组(shortcutItems), 如果需要增加快捷方式,可以赋值给shortcutItems属性。
在方法中 - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
UIApplicationShortcutIcon *icon = [UIApplicationShortcutIcon iconWithTemplateImageName:@"1234"]; UIApplicationShortcutItem *item = [[UIApplicationShortcutItem alloc] initWithType:@"search22" localizedTitle:@"search22" localizedSubtitle:@"0abc" icon:icon userInfo:nil]; application.shortcutItems = @[item];
说明:
1)系统限制每个App最多能够显示4个Action Item,其中包括静态方式和动态方式进行创建的;
2)如果静态和动态方式同时使用的时候,给UIApplication的shortcutItems赋值的时候不会覆盖
3)注,定义的图标 是35x35 的单色图标
当app在后台的时候UIApplication提供了一个回调方法,如下
- (void)application:(UIApplication *)application performActionForShortcutItem:(UIApplicationShortcutItem *)shortcutItem completionHandler:(void(^)(BOOL succeeded))completionHandler{ //判断先前我们设置的唯一标识 if([shortcutItem.type isEqualToString:@"UITouchText.share"]){ NSArray *arr = @[@"hello 3D Touch"]; UIActivityViewController *vc = [[UIActivityViewController alloc]initWithActivityItems:arr applicationActivities:nil]; //设置当前的VC 为rootVC [self.window.rootViewController presentViewController:vc animated:YES completion:^{ }]; } else if ([shortcutItem.type isEqualToString:@"UITouchText.search"]) { UIAlertView *alertView = [[UIAlertView alloc]initWithTitle:@"温馨提示" message:@"好想你" delegate:nil cancelButtonTitle:@"cancel" otherButtonTitles:@"sure", nil]; [alertView show]; } else if ([shortcutItem.type isEqualToString:@"UITouchText.look"]) { UIActionSheet *sheet = [[UIActionSheet alloc]initWithTitle:@"温馨提示" delegate:nil cancelButtonTitle:@"cancel" destructiveButtonTitle:@"删除" otherButtonTitles:@"更多", nil]; [sheet showInView:self.window]; } else if ([shortcutItem.type isEqualToString:@"UITouchText.compose"]) { NSLog(@"UITouchText.compose"); } }
我们依据这个回调中的shortcutItem的type和userinfo来做出不同的事件处理,而最后的completionHandler在API的说明中我们看到当应用并非在后台,而是直接重新开进程的时候,直接返回No,那么这个时候,我们的回调会放在
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
UIApplication又给我们一个从launchOptions中获取这个shortcutItem的key(UIApplicationLaunchOptionsShortcutItemKey)
UIApplicationShortcutItem *item = [launchOptions valueForKey:UIApplicationLaunchOptionsShortcutItemKey]; //根据不同的Action响应不同的事件
Peek and Pop(预览和详阅)
如同使用放大镜拉近视角,预览(Peek)内容(照片、视频)让你可以获得更多信息而不需要加载完整内容。
Instagram首先将Peek功能添加到了小图片和视频上。
Peek(预 览)和Pop(详阅)相关的API为UIViewControllerPreviewingDelegate,它通过view来注册。在 Instagram中,我们只将其注册到可以接受到touch事件的controller的view上。当3D touch事件发生时,delegate来检测view中的哪个对象被点击。
如果delegate判断有Peek(预览)动作发生,它仍需要处理两件事情:1. 设置预览动作发生的view的rect;2. 返回展示的viewcontroller。
当3D touch发生时,会传递给你context信息,包含源view和点击发生的point。自定义的delegate需要通过这个point映射到一个view,然后查找到需要预览的数据。
大多数的Instagram功能基于UICollectionView和UITableView实现。这两者在数据和UI间对应方面都有不错的API支持。
- (UIViewController *)previewingContext:(id)previewingContext viewControllerForLocation:(CGPoint)location { UICollectionView *collectionView = (UICollectionView *)[previewingContext sourceView]; NSIndexPath *indexPath = [collectionView indexPathForItemAtPoint:location]; if (indexPath) { IGPostCell *cell = [collectionView cellForItemAtIndexPath:indexPath]; [previewingContext setSourceRect:cell.frame]; IGPost *post = self.feedController.posts[indexPath.row]; IGThumbnailPreviewController *controller = [[IGThumbnailPreviewController alloc] initWithPost:post]; return controller; } // no peek return nil; }
将预览相关的API和现有的view和功能结合后,查看Instagram照片和视频变的异常简单
我们为header和comment中的用户名添加了查看信息的功能。用来预览用户信息的delegate和显示照片/视频的实现类似:
使用3D touch点击的location和查找到的index path找到对应的cell。
将点击的point关联转换到cell中的textview上。
通过该point获取到text view中的attributed string的属性。
如果找到了用户名称的属性,则返回IGUserPreviewController。
将这些实现串起来,看起来就像这样:
混合内容展示
Instagram中的activity feed功能包含了用户的tag和缩略图。我们之前分别创建过UIViewControllerPreviewingDelegate的对象,用来显示这两种内容。这里我们需要把这些组合在一起。
拷贝已有代码到新的delegate中的做法并不明智。我们选择使用composition模式来组合profile和post展示的delegate代码,这样创建一个新的对象,只需要传递touch 事件即可。
@interface IGUserThumbnailPreviewingHandler : NSObject @property (nonatomic, strong) IGUserPreviewingHandler *userDelegate; @property (nonatomic, strong) IGFeedThumbnailPreviewingHandler *thumbnailDelegate; @end - (UIViewController *)previewingContext:(idUIViewControllerPreviewing>)previewingContext viewControllerForLocation:(CGPoint)location { id controller = [self.thumbnailDelegate previewingContext:previewingContext viewControllerForLocation:location]; if (!controller) { controller = [self.userDelegate previewingContext:previewingContext viewControllerForLocation:location]; } return controller; }
用来显示预览的controller只是UIViewController的子类,在某些特别属性上有所不同。
一开始,controller完全无法交互,你无法在上面点击按钮或添加自定义手势。这里我们需要提供遵循UIPreviewActionItem协议的对象组成的数组。在Instagram中,我们只用UIPreviewActions。
这些功能看起来很像UIAlertController的action item。
在整个Instagram程序中,我们只在需要的时候加载数据,并缓存以备以后使用。这样做既节省了网络等待的时间,又不会浪费用户的带宽。
有 时,当预览用户profile时,我们获取的数据还不足以用来显示最新照片或关注者数量。预览用的view controller仍然会调用viewDidLoad, viewWillAppear:和其他UIViewController事件。在其中可以获取网络数据并更新UI。
最后,我们发现可以通过修改controller的preferredContentSize来调整预览视图的大小,即便是controller已经展示了,这样的改变仍可生效。不过,这个属性无法作用于动画中。
参考:http://git.devzeng.com/blog/ios9-3d-touch.html?utm_source=tuicool&utm_medium=referral
http://engineering.instagram.com/posts/465414923641286/lessons-learned-with-3D-touch
http://www.cocoachina.com/ios/20151110/14129.html
标签:
原文地址:http://www.cnblogs.com/dhui69/p/5413839.html