3D Touch實踐講解 --解決開發中的困惑點

3D Touch是我一直想學習的功能,晚上無意間在手機上按壓了不同的應用(這么一說暴露了自己用的iPhone 6以上的設備),發現常用的應用都加了該功能。為了自己的好奇心,跟著官方文檔做了一遍,把過程中的思路和易錯點記錄下來。

目前3D Touch功能只能在iPhone6并且支持3D Touch的設備中使用

1 主屏幕Icon的3D Touch效果

對于能開啟3D Touch 的設備而言,在主屏幕中以一定的力度按壓應用的圖標,會彈出一個預覽的功能框,功能框中包括一些功能的快捷按鈕,點擊之后會啟動應用并快捷的開啟應用相關功能。具體的實現的步驟如下:

主屏幕Icon按壓效果
步驟一 UIApplicationShortcutItem 添加快捷按鈕

每一個快捷按鈕都是一個UIApplicationShortcutItem,可以通過兩種方法設置:

① 在應用的Info.plist文件中設置靜態快捷按鈕
Info.plist文件中添加快捷按鈕

這種方法很簡單,在UIApplicationShortcutItems鍵中添加快捷鍵的信息。UIApplicationShortcutItem屬性包括:
UIApplicationShortcutItemType(必選):快捷鍵的唯一標識符,用來識別以便于實現相對應的功能
UIApplicationShortcutItemTitle(必選):標題,黑色字體
UIApplicationShortcutItemIconType(可選):顯示的圖標,圖標可以是系統或者自定義
UIApplicationShortcutItemUserInfo(可選):用戶自定義信息
UIApplicationShortcutItemSubtitle(可選):副標題,灰色字體

② 在應用中設置動態快捷按鈕
UIApplicationShortcutIcon *icon = [UIApplicationShortcutIcon iconWithTemplateImageName:@"pay-select.png"];
UIApplicationShortcutItem *home = [[UIApplicationShortcutItem alloc] initWithType:@"lizhou.home" localizedTitle:@"熱門單品" localizedSubtitle:@"熱賣的物品任你挑" icon:icon userInfo:nil];
[UIApplication sharedApplication].shortcutItems = @[home];

重點

1.設置Item的title和subtitle

title和subtitle分別只占用一行,多余的文本系統會默認添加省略號。


系統默認添加省略號效果圖
2.設置icon

快捷鍵的圖標可選擇自定義圖標或系統提供的圖標。自定義的圖片大小應為35x35,而且因為系統會統一模糊化圖片,所以提供的圖標盡量為單色,不然只有可能只顯示黑色的正方形而不使用提供的圖標。

@interface UIApplicationShortcutIcon : NSObject <NSCopying>
// 使用系統提供的圖片
+ (instancetype)iconWithType:(UIApplicationShortcutIconType)type;
// 創建自定義的圖片,將會使圖片模糊成系統定義icon的風格
+ (instancetype)iconWithTemplateImageName:(NSString *)templateImageName;
@end

自定義圖標在Info.plist中可以直接填圖片的名稱。

3. UIApplicationShortcutItemUserInfo 用戶自定義信息

之前一直不能理解靜態和動態設置快捷鍵之間有什么差別,看了幾個應用如微信、微博、支付寶等都是普通的快捷鍵,直到看到快看漫畫,該應用的"繼續閱讀"項中添加了動態的效果,才意識到兩者之間最大的差異性就是UIApplicationShortcutItemUserInfo這個屬性。

快看漫畫動態快捷鍵效果圖
4. 快捷鍵的數量
問題:在官方文檔中明確的標記了應用最多只能設置4個自定義的item,為什么快看會有5個按鈕?
回答:快看漫畫中自定義的item就是四個,最后一個 "分享 ‘快看漫畫’"項是蘋果為每一個提交到應用商店的應用默認添加的,所以準確的說:

開發者自定義的item最多為4個,用戶可視化的item最多為5個

步驟二 識別到用戶對快捷鍵的點擊

應用識別是由3D Touch的點擊進行應用并執行相關的行為的方法分為兩種情況:
① 應用處于運行中的狀態

//app仍然在運行的時候,點擊菜單項會觸發以下的方法:
-(void)application:(UIApplication *)application performActionForShortcutItem:(UIApplicationShortcutItem *)shortcutItem completionHandler:(void (^)(BOOL))completionHandler
{
    if([shortcutItem.type hasSuffix:@"search"]){
        //  搜索更多
    } else if ([shortcutItem.type hasSuffix:@"share"]) {
        //分享
        NSString *title =shortcutItem.localizedTitle;
        
        NSDictionary *userInfo = shortcutItem.userInfo;
        
        UINavigationController *nav = (UINavigationController *)[_tabBarController selectedViewController];
        
        [nav pushViewController:[[TestViewController alloc] init] animated:YES];
    }
    completionHandler(YES);
}

② 應用被kill后,沒有運行的情況下

//在app 被kill的時候,點擊菜單項會觸發以下的方法:
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
  _isEnterFrom3DTouch = true;
 //如果是通過3D Touch點擊shortItem進入應用的話,那么UIApplicationLaunchOptionsShortcutItemKey一定返回相應的UIApplicationShortcutItem。
    UIApplicationShortcutItem *shortItem =[launchOptions objectForKey:UIApplicationLaunchOptionsShortcutItemKey];
    if (shortItem) {
//如果從3D Touch點擊item進行,那么返回false,不再觸發-(void)application:(UIApplication *)application performActionForShortcutItem:(UIApplicationShortcutItem *)shortcutItem completionHandler:(void (^)(BOOL))completionHandler方法
        _isEnterFrom3DTouch = false;
    }
  return _isEnterFrom3DTouch;
}

其實在設置item和收到item 的用戶響應都不需要判斷設備是否支持3D Touch,如果支持,按壓才能識別。識別之后系統才會執行應用設置的3D Touch功能。

對于Icon設置的3D Touch以及相關的響應接收方法處理差不多了,下面是對應用內的3D Touch配置。

2 應用內的3D Touch效果

3D Touch效果圖

上圖中能清楚的看到整個過程包括兩個階段:
第一階段 :模糊化周圍,彈出一個類似彈框的界面 ----peek
第二階段:加重按壓,進入一個視圖控制器 --- pop

實現整個效果的步驟如下:

步驟一 明確哪個控件有3D Touch功能并注冊

像微博,一個cell中有兩個3D Touch控件,而且兩個控件的預覽圖也不同,并且點擊在cell別的地方時不會顯示3D Touch的效果。

微博添加3D Touch控件位置

所以需要對一個cell內部局部view進行3D Touch的注冊,而不是像官方例子中對整個tableView進行注冊:

if (self.traitCollection.forceTouchCapability == UIForceTouchCapabilityAvailable) {
        [self registerForPreviewingWithDelegate:self sourceView:self.tableView];
    }

對于整體而言,首先我們注冊的是具有3D Touch功能的控件 ---cell中的imageView(以微博為例),所以cell需要實現UIViewControllerPreviewingDelegate協議

@interface LZImageCell : UITableViewCell<UIViewControllerPreviewingDelegate>

并且實現UIViewControllerPreviewingDelegate協議的兩個方法:

//顯示 pop 的視圖控制器
-(void)previewingContext:(id<UIViewControllerPreviewing>)previewingContext commitViewController:(UIViewController *)viewControllerToCommit
{
    if ([self.previewDelegate respondsToSelector:@selector(previewingContext:commit:)]) {
        [self.previewDelegate previewingContext:previewingContext commit:viewControllerToCommit];
    }
}
//顯示peek 的視圖控制器
-(UIViewController *)previewingContext:(id<UIViewControllerPreviewing>)previewingContext viewControllerForLocation:(CGPoint)location
{
    if ([self.previewDelegate respondsToSelector:@selector(previewingContext:viewControllerForLocation:)]) {    
        return [self.previewDelegate previewingContext:previewingContext location:location];
    }
    return nil;
}

因為cell本身是無法處理視圖控制器之間的push,并且注冊只能在ViewController類中注冊,所以設置一個delegate,將數據傳遞到相應的viewController中進行處理:

-(UIViewController *)previewingContext:(id<UIViewControllerPreviewing>)previewingContext location:(CGPoint)location
{
//根據點擊位獲得當前點擊cell的indexPath值
    NSIndexPath *indexpath = [self.tableView indexPathForRowAtPoint:location];
  //得到當前點擊的cell的位置
    CGRect cellFrame = [self.tableView cellForRowAtIndexPath:indexpath].frame;
    //找到cell中響應3D Touch的圖片控件位置和大小
    cellFrame.size.height = 200;
    cellFrame.origin.x = 10;
    cellFrame.size.width = [UIScreen mainScreen].bounds.size.width - 20;

    TestViewController *test = [[TestViewController alloc] init];
//這個值是設置顯示test控制器中view的大小
    test.preferredContentSize = CGSizeMake([UIScreen mainScreen].bounds.size.width - 20, 200);
//周圍都是模糊化,只有cellFrame值設置的部分為清晰的狀態
    previewingContext.sourceRect = cellFrame;
    return test;
}
//pop 顯示視圖控制器
//commitViewController是在peek方法中設置的ViewController(如: TestViewController)
-(void )previewingContext:(id<UIViewControllerPreviewing>)previewingContext commit:(UIViewController *)commitViewController
{
    [self.navigationController pushViewController:commitViewController animated:YES];
}

將peek和pop設置完成之后,只差最后一步了 ---- 注冊cell中的imageView

-(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
    LZImageCell *cell = [tableView dequeueReusableCellWithIdentifier:imageCellStr forIndexPath:indexPath];
    
    cell.previewDelegate = self;
    
    if (self.traitCollection.forceTouchCapability == UIForceTouchCapabilityAvailable) {
        //注冊
        [self registerForPreviewingWithDelegate:cell sourceView:cell.backImageView];
    } else {
        NSLog(@"3D Touch 不可用");
    }
    return cell;
}

注意:如果你還按壓imageView沒有任何反應,說明你沒有將圖片的交互功能打開

backImageView.userInteractionEnabled = YES;

按壓也是touch的一種,需要響應的,是不是傻??!

步驟二 對預覽頁中添加按鈕

用戶在peek頁中向上滑動會出現設置的按鈕,所以按鈕設置在peek方法返回的ViewController中(如:TestViewController)

在peek頁中添加按鈕
-(NSArray<id<UIPreviewActionItem>> *)previewActionItems
{
    UIPreviewAction *likeAction = [UIPreviewAction actionWithTitle:@"喜歡" style:UIPreviewActionStyleDefault handler:^(UIPreviewAction * _Nonnull action, UIViewController * _Nonnull previewViewController) {
        
    }];
    
    UIPreviewAction *cancleAction = [UIPreviewAction actionWithTitle:@"保存" style:UIPreviewActionStyleDefault handler:^(UIPreviewAction * _Nonnull action, UIViewController * _Nonnull previewViewController) {
        
    }];

官方文檔自己都說設置的UIPreviewAction按鈕和UIAlertAction很類似,所以對于style的設置沒什么不同。

如果按鈕數過多,可以將類似的按鈕放在同一個按鈕組中


設置按鈕組

點擊之后才會顯示相關的按鈕。


就我個人認為實現3D Touch的實現并不難,但是有一些細節和思路還是要好好優化,等將官方的相關文檔全部看了一遍之后,再好好總結一次。

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 228,461評論 6 532
  • 序言:濱河連續發生了三起死亡事件,死亡現場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發現死者居然都...
    沈念sama閱讀 98,538評論 3 417
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事?!?“怎么了?”我有些...
    開封第一講書人閱讀 176,423評論 0 375
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 62,991評論 1 312
  • 正文 為了忘掉前任,我火速辦了婚禮,結果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當我...
    茶點故事閱讀 71,761評論 6 410
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發上,一...
    開封第一講書人閱讀 55,207評論 1 324
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當著我的面吹牛,可吹牛的內容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,268評論 3 441
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 42,419評論 0 288
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當地人在樹林里發現了一具尸體,經...
    沈念sama閱讀 48,959評論 1 335
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 40,782評論 3 354
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發現自己被綠了。 大學時的朋友給我發了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 42,983評論 1 369
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 38,528評論 5 359
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質發生泄漏。R本人自食惡果不足惜,卻給世界環境...
    茶點故事閱讀 44,222評論 3 347
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 34,653評論 0 26
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 35,901評論 1 286
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 51,678評論 3 392
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 47,978評論 2 374

推薦閱讀更多精彩內容

  • Android 自定義View的各種姿勢1 Activity的顯示之ViewRootImpl詳解 Activity...
    passiontim閱讀 172,660評論 25 708
  • 獨有特性 列表不同于元組和字符串的地方:可變 特殊函數 函數list可以把其他序列轉換為列表 python 3.0...
    chf041閱讀 314評論 0 0
  • 上午的隨手拍 水果店的叔叔阿姨笑起來超暖 煎餅店的姐姐剪刀手超可愛
    長吉玉川閱讀 227評論 0 3
  • 今天聽音頻,聽到一句話,特別感同身受。 “你身邊五個朋友能力的平均值,就是你的能力值。” 就像之前提到的一句話,你...
    一樹綠葉閱讀 483評論 2 2
  • 少年錦時丶楠海 你好,我是楠海。感謝你點開我的文章。寫這樣一期內容,就是想和關注我的朋友做一個交流。端一杯咖啡,享...
    行者楠海閱讀 217評論 0 3