在iOS9 中使用3D Touch

iOS9提供了四類API( Home Screen Quick ActionUIKit Peek & PopWebView Peek & PopUITouch Force Properties )用於操做3D Touch。不過不管使用哪種API,首先須要作的事情是檢查3D Touch是否可用。css

檢測是否支持3D Touch

在iOS9中提供以下的接口用於檢查設備是否支持3D Touch:html

@property(nonatomic, readonly) UIForceTouchCapability forceTouchCapability;

其中 UIForceTouchCapability 是一個枚舉類型,具體的描述狀況以下:ios

  • UIForceTouchCapability
    • UIForceTouchCapabilityUnknown //3D Touch檢測失敗
    • UIForceTouchCapabilityUnavailable //3D Touch不可用
    • UIForceTouchCapabilityAvailable //3D Touch可用

這3個枚舉值就是咱們來判斷設備是否開啓3D Touch功能,能夠在UIViewController生命週期的viewWillAppear中作以下判斷:git

if (self.traitCollection.forceTouchCapability == UIForceTouchCapabilityAvailable) {
  //do something
}

固然在生命週期內,若是用戶有意修改了設備的3D Touch功能,咱們還有一個地方來從新檢測:數組

- (void)traitCollectionDidChange:(UITraitCollection *)previousTraitCollection {
  //do something
}

Home Screen Quick Action

建立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已經展現了,這樣的改變仍可生效。不過,這個屬性沒法做用於動畫中。

 ios 3D Touch功能的實現

 

參考: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

相關文章
相關標籤/搜索