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

一、簡(jiǎn)介

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

  1. 通過(guò)按鈕屏幕上的APP圖標(biāo),彈出選項(xiàng)菜單,可快速進(jìn)入APP里面的某個(gè)頁(yè)面
  2. 在APP內(nèi)部,通過(guò)按壓某個(gè)控件,預(yù)覽下一頁(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 操作
它可通過(guò) 靜態(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 方法中通過(guò)函數(shù)來(lái)創(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)入了搜索頁(yè)面";
        
    } 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 {
    }
    // 這里的頁(yè)面跳轉(zhuǎn)是一個(gè)例子,具體根據(jù)實(shí)際項(xiàng)目做,意思是先獲取根視圖,新建要跳轉(zhuǎn)的控制器,然后prensen 或 push 頁(yè)面即可
    [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 即跳到下一頁(yè)了

// 繼續(xù)用力按下進(jìn)入下一頁(yè)(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)的處理事件寫(xiě)在里面
- (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 里面需要重寫(xiě) previewActionItems 方法

@property (nonatomic, strong) NSArray *recordPreviewActionItems;

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

好了,方法就是這些了,下面就介紹下 Swift 中的寫(xiě)法吧

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 = "搜索頁(yè)面"
        default:
             nextVc.name = "直播頁(yè)面"
        }
        rootVc?.present(nextVc, animated: true, completion: nil)
    }

列表 TableViewController_A:

class TableViewController_A: UITableViewController ,UIViewControllerPreviewingDelegate{

    /// 詳情頁(yè)預(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) 行過(guò)來(lái)的"
        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)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容