一稚字、簡(jiǎn)介
3D Touch 是在 6s 以上手機(jī)才可以使用的一個(gè)功能,通過按壓屏幕厦酬,做出相應(yīng)的響應(yīng)事件胆描,交互性特別好。
它在項(xiàng)目中仗阅,主要有以下兩個(gè)應(yīng)用:
- 通過按鈕屏幕上的APP圖標(biāo)昌讲,彈出選項(xiàng)菜單,可
快速進(jìn)入
APP里面的某個(gè)頁面- 在APP內(nèi)部减噪,通過按壓某個(gè)控件剧蚣,
預(yù)覽
下一頁的內(nèi)容,繼續(xù)按壓可進(jìn)入詳情
二旋廷、應(yīng)用圖標(biāo)按壓快速進(jìn)入APP
具體效果圖
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)鍵字礼搁,并做如下配置
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
- 要使用 預(yù)覽(peek)功能厨姚,需要在當(dāng)前控制器中遵守
UIViewControllerPreviewingDelegate
協(xié)議
@interface TableViewController_A ()<UIViewControllerPreviewingDelegate>
@end
-
實(shí)現(xiàn)用力按下 cell衅澈, 彈出預(yù)覽,如圖
首先需要 注冊(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),如下圖
你只需要兩步:
- 在當(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;
}
- 賦值給下一個(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 ?? []
}
}