本文由CocoaChina譯者Leon(社區ID)翻譯自Instagram的博客
作者:Ryan Nystrom
原文:Lessons learned with 3D Touch
(注:文章發布時間為10月2日)
上周,Apple發布了最新的iPhone產品線,從iPhone 6s開始,產品都添加了一項硬件屬性,叫做3D touch。作為屏幕的一部分,新的傳感器將能識別用力按下屏幕的動作並檢測到精確的壓力變化。
同新的硬件一起,Apple發布了3個新的API,幫助開發者為App添加另一維度的交互。”Quick Actions”讓你在點擊app圖標時選擇四個菜單項。另一個功能可以讓你“預覽”某項內容,然後展示內部更詳細的信息。最後一個API通過UITouch對象提供給開發者按壓動作的詳情,比如力度和maximumPossibleForce。
我們有機會在這項新功能發布之初就集成它到Instagram中。在添加了shortcuts和peeking功能後,照片和視頻看起來是如此自然,這很讓人驚喜。這些新的API在添加3D交互功能時銜接自然,我們整理了實施時的一些要點。
快捷操作(Quick Actions)
快捷操作讓用戶可以快速跳轉到app的某項功能中,而忽略掉中間步驟。例如在Instagram中,我們添加最常用的幾項功能到快捷操作中:Search, Direct, Activity和Creation.
(點擊查看動圖)
在主界面添加快捷操作相當簡單,只需要創建UIApplicationShortcutItems的數組,並添加到app的delegate中。每個item都有一個代表類型的字符串和可選的UIApplicationShortcutIcon作為icon。
在Instagram中,我們創建了UIApplicationShortcutItem的擴展,用來創建快捷方式。
+ (instancetype)ig_searchItem { NSString *title = NSLocalizedString(@"Search", nil); UIApplicationShortcutIcon *icon = [UIApplicationShortcutIcon iconWithTemplateImageName:@"search"]; UIApplicationShortcutItem *item = [[UIApplicationShortcutItem alloc] initWithType:@"search" localizedTitle:title localizedSubtitle:nil icon:icon userInfo:nil]; return item; }
根據用戶是否登錄的條件,我們動態的配置快捷方式的item:
application.shortcutItems = @[ [UIApplicationShortcutItem ig_postItem], [UIApplicationShortcutItem ig_activityItem], [UIApplicationShortcutItem ig_searchItem], [UIApplicationShortcutItem ig_directItem] ];
我們的架構已經處理過諸如app鏈接和推送通知的流程,因此只需要在-application:performActionForShortcutItem:completionHandler:方法中調用對應的流程即可。
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已經展示了,這樣的改變仍可生效。不過,這個屬性無法作用於動畫中。
結論
對於Instagram來說,3D touch是2015年版本的“右鍵點擊”。它添加了另一種深度,帶來了不同的交互意向:你可能還沒有決定跳轉到某個內容上去,但你肯定會對它感興趣。只要有這種想法,預覽內容的功能可以讓你對眼前內容快速一瞥,而不跳轉頁面,這樣可以快速返回到之前浏覽的內容中。
快捷操作讓你能夠直接跳轉到創建新帖子的步驟中,也可以讓你快速查看Instagram中最近發生了些什麼,而不需要啟動程序後,一步一步的點擊。在“簡約”理念的指導下,快捷操作讓Instagram更好用。