3D Touch 在 OC 稳摄、Swift 中的實(shí)際應(yīng)用

一稚字、簡(jiǎn)介

3D Touch 是在 6s 以上手機(jī)才可以使用的一個(gè)功能,通過按壓屏幕厦酬,做出相應(yīng)的響應(yīng)事件胆描,交互性特別好。
它在項(xiàng)目中仗阅,主要有以下兩個(gè)應(yīng)用:

  1. 通過按鈕屏幕上的APP圖標(biāo)昌讲,彈出選項(xiàng)菜單,可快速進(jìn)入APP里面的某個(gè)頁面
  2. 在APP內(nèi)部减噪,通過按壓某個(gè)控件剧蚣,預(yù)覽下一頁的內(nèi)容,繼續(xù)按壓可進(jìn)入詳情

二旋廷、應(yīng)用圖標(biāo)按壓快速進(jìn)入APP

具體效果圖


圖片.png
圖片.png

ShortcutItem 功能用于實(shí)現(xiàn)對(duì) 應(yīng)用圖標(biāo) 的3D Touch 操作
它可通過 靜態(tài)、動(dòng)態(tài) 兩種方式添加到項(xiàng)目中

1. 靜態(tài)添加

info.plist 中添加 UIApplicationShortcutItems 關(guān)鍵字礼搁,并做如下配置

圖片.png

UIApplicationShortcutItems : 表示選項(xiàng)列表
UIApplicationShortcutItemType: 每個(gè) item 的唯一標(biāo)識(shí)
UIApplicationShortcutItemTitle: 標(biāo)題
UIApplicationShortcutItemSubtitle: 子標(biāo)題(可不填)
UIApplicationShortcutItemIconType: 圖標(biāo)(可使用自定義圖標(biāo))

2.動(dòng)態(tài)添加 (推薦使用)

除了在 plist 文件中配置外饶碘,我們還可以在 appdelegate 方法中通過函數(shù)來創(chuàng)建 UIApplicationShortcutItem 如下:

UIApplicationShortcutIcon *searchIcon = [UIApplicationShortcutIcon iconWithType:UIApplicationShortcutIconTypeSearch];
UIApplicationShortcutItem *searceItem = [[UIApplicationShortcutItem alloc]
                                             initWithType:@"com.268.search"
                                             localizedTitle:@"搜索"
                                             localizedSubtitle:nil
                                             icon:searchIcon
                                             userInfo:nil];

上面創(chuàng)建的圖標(biāo) UIApplicationShortcutIcon 是使用系統(tǒng)自帶的,也可以自己創(chuàng)建,如下

// 這里可以自定義圖標(biāo)馒吴,不使用系統(tǒng)的 icon, 推薦尺寸是 35*35扎运,單色(因?yàn)橄到y(tǒng)會(huì)把圖片渲染成灰黑色)
    UIApplicationShortcutIcon *livingIcon = [UIApplicationShortcutIcon iconWithTemplateImageName:@"我的_我的直播"];

每一個(gè) item 都是一個(gè)選項(xiàng),最后加入到 application.shortcutItems數(shù)組即可

application.shortcutItems = @[searceItem,livingItem,courseItem,messageItem];

由于 UIApplicationShortcutItem 創(chuàng)建方法是在 iOS 9 以后的饮戳,所以為了防止之前的機(jī)型調(diào)用此方法崩潰豪治,所以在調(diào)用上述方法前,最好加一個(gè)驗(yàn)證

    // 監(jiān)測(cè) 3D Touch 是否可用
    if ([self respondsToSelector:@selector(traitCollection)]) {
        if ([self.window.traitCollection respondsToSelector:@selector(forceTouchCapability)]) {
            if (self.window.traitCollection.forceTouchCapability != UIForceTouchCapabilityAvailable) {
                return;
            }
        }
    }

3. UIApplicationShortcutItem 回調(diào)方法

當(dāng)點(diǎn)擊圖標(biāo)快捷選項(xiàng)時(shí)扯罐,會(huì)調(diào)用 AppDelegate 中的回調(diào)方法

-(void)application:(UIApplication *)application performActionForShortcutItem:(UIApplicationShortcutItem *)shortcutItem completionHandler:(void (^)(BOOL))completionHandler {

我們?cè)诶锩孀鱿鄳?yīng)操作即可负拟,如下

-(void)application:(UIApplication *)application performActionForShortcutItem:(UIApplicationShortcutItem *)shortcutItem completionHandler:(void (^)(BOOL))completionHandler {
    
    ChXDemoViewController *demoVC = [[NSClassFromString(@"ChXDemoViewController") alloc] init];

    if ([shortcutItem.type isEqualToString:@"com.268.search"]) { // 搜索
//        UIViewController *searchVc = [[NSClassFromString(@"SearchViewController") alloc] init];
//        [self.mainController pushViewController:searchVc animated:YES];
        demoVC.titleName = @"進(jìn)入了搜索頁面";
        
    } else if ([shortcutItem.type isEqualToString:@"com.268.message"]) { // 系統(tǒng)消息
//        if ([USERID integerValue] != 0) {
//            UIViewController *nextVc = [[NSClassFromString(@"NoticeViewController") alloc]init];
//            [self.mainController pushViewController:nextVc animated:NO];
//        } else {
////            [self showLoginViewController:self.mainController];
//        }
        
        demoVC.title = @"進(jìn)入消息";
    } else if ([shortcutItem.type isEqualToString:@"com.268.course"]) {
//        if ([USERID integerValue] != 0) {
//            UIViewController *nextVC = [[NSClassFromString(@"MyCourseTableViewController") alloc] init];
////            [self.mainController pushViewController:nextVC animated:NO];
//        } else {
////            [self showLoginViewController:self.mainController];
//        }
        demoVC.title = @"進(jìn)入課程";

    } else if ([shortcutItem.type isEqualToString:@"com.268.living"]) {
//        if ([USERID integerValue] != 0) {
//            UIViewController *nextVC = [[NSClassFromString(@"ChXMyLiveController") alloc] init];
////            [self.mainController pushViewController:nextVC animated:NO];
//        } else {
////            [self showLoginViewController:self.mainController];
//        }
        demoVC.title = @"進(jìn)入直播";

    } else {
    }
    // 這里的頁面跳轉(zhuǎn)是一個(gè)例子,具體根據(jù)實(shí)際項(xiàng)目做歹河,意思是先獲取根視圖掩浙,新建要跳轉(zhuǎn)的控制器花吟,然后prensen 或 push 頁面即可
    [self.window.rootViewController presentViewController:demoVC animated:YES completion:nil];
}

三、APP 內(nèi)部預(yù)覽 peek & pop

  1. 要使用 預(yù)覽(peek)功能厨姚,需要在當(dāng)前控制器中遵守 UIViewControllerPreviewingDelegate 協(xié)議
@interface TableViewController_A ()<UIViewControllerPreviewingDelegate>
@end
  1. 實(shí)現(xiàn)用力按下 cell衅澈, 彈出預(yù)覽,如圖


    圖片.png

首先需要 注冊(cè) cell 可以預(yù)覽, 在 cellForRowAtIndexPath中輸入下面代碼

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
    UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:@"cellId" forIndexPath:indexPath];
    cell.textLabel.text = [NSString stringWithFormat:@"第%ld行",(long)indexPath.row];
    
    // 注冊(cè)需要實(shí)現(xiàn) Touch 效果的view谬墙, 這里是 用力按下cell,彈出預(yù)覽小視圖今布,同時(shí)上滑底部出現(xiàn)若干個(gè)選項(xiàng)(peek功能)
    // 首先判斷設(shè)備系統(tǒng)是否支持,否則會(huì)崩潰
    if ([self respondsToSelector:@selector(traitCollection)]) {
        if ([self.traitCollection respondsToSelector:@selector(forceTouchCapability)]) {
            if (self.traitCollection.forceTouchCapability == UIForceTouchCapabilityAvailable) {
                [self registerForPreviewingWithDelegate:self sourceView:cell];
            }
        }
    }
    
    return cell;
}

然后實(shí)現(xiàn) UIViewControllerPreviewingDelegate中的代理方法 commitViewController 即跳到下一頁了

// 繼續(xù)用力按下進(jìn)入下一頁(pop)
- (void)previewingContext:(id<UIViewControllerPreviewing>)previewingContext commitViewController:(UIViewController *)viewControllerToCommit {
    [self presentViewController:viewControllerToCommit animated:YES completion:nil];
}

如果你希望拭抬,在預(yù)覽的圖向上滑動(dòng)時(shí)部默,有菜單選項(xiàng),如下圖


圖片.png

你只需要兩步:

  1. 在當(dāng)前控制器創(chuàng)建一個(gè) UIPreviewAction的數(shù)組,并把相應(yīng)的處理事件寫在里面
- (NSArray *)recordPreviewActionItems {
    if (!_recordPreviewActionItems) {
        UIPreviewAction *action1 = [UIPreviewAction actionWithTitle:@"刪除" style:UIPreviewActionStyleDestructive handler:^(UIPreviewAction * _Nonnull action, UIViewController * _Nonnull previewViewController) {
//            [self deleteCellWithIndexPath:self.previewCellIndexPath];
            NSLog(@"刪除");
        }];
        UIPreviewAction *action2 = [UIPreviewAction actionWithTitle:@"返回" style:UIPreviewActionStyleDefault handler:^(UIPreviewAction * _Nonnull action, UIViewController * _Nonnull previewViewController) {
            NSLog(@"預(yù)覽返回");
        }];
        _recordPreviewActionItems = @[action1,action2];
    }
    return _recordPreviewActionItems;
}
  1. 賦值給下一個(gè)控制器
    在創(chuàng)建 DetailViewController 控制器的代碼下面玖喘,給recordPreviewActionItems 屬性賦值
detailVc.recordPreviewActionItems = self.recordPreviewActionItems;

DetailViewController 里面需要重寫 previewActionItems 方法

@property (nonatomic, strong) NSArray *recordPreviewActionItems;

#pragma mark - ****************  3D Touch 預(yù)覽時(shí)下方快捷菜單
- (NSArray<id<UIPreviewActionItem>> *)previewActionItems {
    return  self.recordPreviewActionItems;
}

好了甩牺,方法就是這些了,下面就介紹下 Swift 中的寫法吧

Swift 中的代碼

其實(shí)累奈,就是把 OC 的翻譯一下 贬派。。澎媒。

AppDelegate.swift:

 func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {

        configure3DTouch(application: application)

        return true
    }

    /// 配置 3D Touch
    ///
    /// - Parameter application: UIApplication
    func configure3DTouch(application: UIApplication) {

        // 判斷當(dāng)前設(shè)置是否支持 3D Touch
        if #available(iOS 9.0, *) {
            if window?.traitCollection.forceTouchCapability != UIForceTouchCapability.available {
                print("3D touch 不可用")
                return;
            }
        } else {
            print("3D touch 不可用")
            return
        }
    
        // 添加 item
        let searchIcon = UIApplicationShortcutIcon.init(type: .search)
        let searchItem = UIApplicationShortcutItem.init(type: "com.268.search",
                                                        localizedTitle: "搜一搜",
                                                        localizedSubtitle: "點(diǎn)擊進(jìn)入搜索",
                                                        icon: searchIcon,
                                                        userInfo: nil)
        
        let livingIcon = UIApplicationShortcutIcon.init(templateImageName: "我的_我的直播")
        let livingItem = UIApplicationShortcutItem.init(type: "com.268.living",
                                                        localizedTitle: "直播",
                                                        localizedSubtitle: nil,
                                                        icon: livingIcon,
                                                        userInfo: nil)
        application.shortcutItems = [searchItem, livingItem]

    }

    func application(_ application: UIApplication, performActionFor shortcutItem: UIApplicationShortcutItem, completionHandler: @escaping (Bool) -> Void) {
        
        let rootVc = window?.rootViewController
        let nextVc = DemoViewController()
        
        // 根據(jù) type 唯一標(biāo)識(shí)進(jìn)行判斷跳轉(zhuǎn)
        switch shortcutItem.type {
        case "com.268.search":
            nextVc.name = "搜索頁面"
        default:
             nextVc.name = "直播頁面"
        }
        rootVc?.present(nextVc, animated: true, completion: nil)
    }

列表 TableViewController_A:

class TableViewController_A: UITableViewController ,UIViewControllerPreviewingDelegate{

    /// 詳情頁預(yù)覽選項(xiàng)數(shù)組
    private lazy var detailPreviewActionItems = [UIPreviewAction]()
    
    override func viewDidLoad() {
        super.viewDidLoad()

        view.backgroundColor = UIColor.green
        tableView.register(NSClassFromString("UITableViewCell"), forCellReuseIdentifier: "cellId")
        
        configureDetailPreviewItems()
    }

    func configureDetailPreviewItems() {
        let action1 = UIPreviewAction.init(title: "刪除",
                                           style: .destructive) { (_, _) in
                                            print("刪除了~")
        }
        let action2 = UIPreviewAction.init(title: "返回",
                                           style: .default) { (_, _) in
                                            print("返回了~")
        }
        detailPreviewActionItems = [action1, action2]
    }

    // MARK: - Table view data source

    override func numberOfSections(in tableView: UITableView) -> Int {
        // #warning Incomplete implementation, return the number of sections
        return 1
    }

    override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        // #warning Incomplete implementation, return the number of rows
        return 10
    }

    override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
        let cell = tableView.dequeueReusableCell(withIdentifier: "cellId", for: indexPath)
        cell.textLabel?.text = "第 \(indexPath.row) 行"
        
        // 判斷是否支持 3D Touch
        if #available(iOS 9.0, *) {
            if traitCollection.forceTouchCapability == UIForceTouchCapability.available {
                // 注冊(cè) Peek & Pop 功能
                registerForPreviewing(with: self, sourceView: cell)
            }
        }
        
        return cell
    }
    
    func previewingContext(_ previewingContext: UIViewControllerPreviewing, viewControllerForLocation location: CGPoint) -> UIViewController? {
        // 1. 獲取當(dāng)前按壓 cell 所在的行
        guard let cell = previewingContext.sourceView as? UITableViewCell else {
            return UIViewController()
        }
        let indexPath = tableView.indexPath(for: cell) ?? IndexPath(row: 0, section: 0)
        
        // 2. 設(shè)置預(yù)覽界面
        let nextVc = DemoViewController()
        nextVc.name = "第 \(indexPath.row) 行過來的"
        nextVc.items = detailPreviewActionItems
        
        return nextVc
    }
    
    func previewingContext(_ previewingContext: UIViewControllerPreviewing, commit viewControllerToCommit: UIViewController) {
        show(viewControllerToCommit, sender: self)
    }

}

詳情 DemoViewController:

class DemoViewController: UIViewController {

    @IBOutlet weak var titleLabel: UILabel!
    
    var items: [UIPreviewAction]?
    
    /// 標(biāo)題
    var name: String?
    
    override func viewDidLoad() {
        super.viewDidLoad()

        view.backgroundColor = UIColor.groupTableViewBackground
        titleLabel.text = (name ?? "")
    }

    override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
        dismiss(animated: true, completion: nil)
    }
    
    override var previewActionItems: [UIPreviewActionItem] {
        return items ?? []
    }
    
}
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末搞乏,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子戒努,更是在濱河造成了極大的恐慌请敦,老刑警劉巖,帶你破解...
    沈念sama閱讀 206,378評(píng)論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件储玫,死亡現(xiàn)場(chǎng)離奇詭異侍筛,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)撒穷,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,356評(píng)論 2 382
  • 文/潘曉璐 我一進(jìn)店門匣椰,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人端礼,你說我怎么就攤上這事禽笑。” “怎么了蛤奥?”我有些...
    開封第一講書人閱讀 152,702評(píng)論 0 342
  • 文/不壞的土叔 我叫張陵佳镜,是天一觀的道長(zhǎng)。 經(jīng)常有香客問我凡桥,道長(zhǎng)蟀伸,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 55,259評(píng)論 1 279
  • 正文 為了忘掉前任,我火速辦了婚禮望蜡,結(jié)果婚禮上唤崭,老公的妹妹穿的比我還像新娘。我一直安慰自己脖律,他們只是感情好谢肾,可當(dāng)我...
    茶點(diǎn)故事閱讀 64,263評(píng)論 5 371
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著小泉,像睡著了一般芦疏。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上微姊,一...
    開封第一講書人閱讀 49,036評(píng)論 1 285
  • 那天酸茴,我揣著相機(jī)與錄音,去河邊找鬼兢交。 笑死薪捍,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的配喳。 我是一名探鬼主播酪穿,決...
    沈念sama閱讀 38,349評(píng)論 3 400
  • 文/蒼蘭香墨 我猛地睜開眼,長(zhǎng)吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼晴裹!你這毒婦竟也來了被济?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 36,979評(píng)論 0 259
  • 序言:老撾萬榮一對(duì)情侶失蹤涧团,失蹤者是張志新(化名)和其女友劉穎只磷,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體泌绣,經(jīng)...
    沈念sama閱讀 43,469評(píng)論 1 300
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡钮追,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 35,938評(píng)論 2 323
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了阿迈。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片畏陕。...
    茶點(diǎn)故事閱讀 38,059評(píng)論 1 333
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖仿滔,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情犹芹,我是刑警寧澤崎页,帶...
    沈念sama閱讀 33,703評(píng)論 4 323
  • 正文 年R本政府宣布,位于F島的核電站腰埂,受9級(jí)特大地震影響飒焦,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,257評(píng)論 3 307
  • 文/蒙蒙 一牺荠、第九天 我趴在偏房一處隱蔽的房頂上張望翁巍。 院中可真熱鬧,春花似錦休雌、人聲如沸灶壶。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,262評(píng)論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽驰凛。三九已至,卻和暖如春担扑,著一層夾襖步出監(jiān)牢的瞬間恰响,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 31,485評(píng)論 1 262
  • 我被黑心中介騙來泰國(guó)打工涌献, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留胚宦,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 45,501評(píng)論 2 354
  • 正文 我出身青樓燕垃,卻偏偏與公主長(zhǎng)得像枢劝,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子利术,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 42,792評(píng)論 2 345

推薦閱讀更多精彩內(nèi)容