iOS9提供了四類API( Home Screen Quick Action
、 UIKit Peek & Pop
、 WebView Peek & Pop
和 UITouch Force Properties
)用於操做3D Touch。不過不管使用哪種API,首先須要作的事情是檢查3D Touch是否可用。css
在iOS9中提供以下的接口用於檢查設備是否支持3D Touch:html
@property(nonatomic, readonly) UIForceTouchCapability forceTouchCapability;
其中 UIForceTouchCapability
是一個枚舉類型,具體的描述狀況以下:ios
這3個枚舉值就是咱們來判斷設備是否開啓3D Touch功能,能夠在UIViewController生命週期的viewWillAppear中作以下判斷:git
if (self.traitCollection.forceTouchCapability == UIForceTouchCapabilityAvailable) { //do something }
固然在生命週期內,若是用戶有意修改了設備的3D Touch功能,咱們還有一個地方來從新檢測:數組
- (void)traitCollectionDidChange:(UITraitCollection *)previousTraitCollection { //do something }
建立Quick Action有兩種方式:靜態和動態緩存
①以靜態方式建立網絡
靜態建立的方式是在Info.plist文件中進行聲明的app
<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>
②以動態方式建立less
動態建立是在程序初始化的時候用代碼動態添加。 UIApplication
對象多了一個支持快捷方式的數組(shortcutItems), 若是須要增長快捷方式,能夠賦值給shortcutItems屬性。post
在方法中 - (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