3D-touch API - Peek and Pop
3D-touch目前有两种使用方式
- Home Screen Quick Actions 应用图标的快捷按钮
- Peek and Pop 预览,窥探
Peek and Pop
预览弹出功能
先判断设备是否支持3D-touch
Checking for 3D Touch Availability
To check at runtime whether a device supports 3D Touch, read the value of the forceTouchCapability property on the trait collection for any object that has a trait environment (seeUITraitEnvironment Protocol Reference). A user can turn off 3D Touch while your app is running, so read this property as part of your implementation of the traitCollectionDidChange: delegate method.
To ensure that all your users can access your app’s features, branch your code depending on whether 3D Touch is available. When it is available, take advantage of 3D Touch capabilities. When it is not available, provide alternatives such as by employing touch and hold, implemented with the UILongPressGestureRecognizer class.
Refer to iOS Human Interface Guidelines for ideas on how to enhance your app’s interactions for users with 3D Touch-capable devices while not leaving your other users behind.
//判断是否支持3D-Touch
if (self.traitCollection.forceTouchCapability == UIForceTouchCapabilityAvailable) {
//支持就注册代理
[self registerForPreviewingWithDelegate:(id)self sourceView:self.tableView];
} else {
//不支持
NSLog(@"3D Touch is not available on this device.");
}
注册代理和sourceView
当判断设备支持3D-touch后,我们要进行注册代理和sourceView.
代理方法是用来实现预览和弹出的主要方法.
sourceView可以理解为这个view可以支持3D-touch,而且我们后面的计算非模糊区域的时候,坐标是根据sourceView来的.
//支持就注册代理
[self registerForPreviewingWithDelegate:(id)self sourceView:self.tableView]
遵守UIViewControllerPreviewingDelegate,并实现代理方法
UIViewControllerPreviewingDelegate简介
Implement the methods of this protocol to respond, with a preview view controller and a commit view controller, to the user pressing a view object on the screen of a device that supports 3D Touch.
主要方法
第一个代理方法:
- (UIViewController *)previewingContext:(id<UIViewControllerPreviewing>)previewingContext viewControllerForLocation:(CGPoint)location;
Called when the user has pressed a source view in a previewing view controller, thereby obtaining a surrounding blur to indicate that a preview (peek) is available.
当用户重压一个支持3D-touch的区域的时候(Peek),会调用这个方法,除了sourceRect其他区域会变模糊,通过这种方式来提醒你预览的区域.
参数:
- previewingContext 预览上下文
- 可以用来设置sourceRect
- location 重压点
- 你进行3D-touch按压的坐标
- 这个坐标是相对于sourceView的
返回值:
- 返回需要预览的控制器
第二个代理方法:
- (void)previewingContext:(id<UIViewControllerPreviewing>)previewingContext commitViewController:(UIViewController *)viewControllerToCommit
Called to let you prepare the presentation of a commit (pop) view from your commit view controller.
当你预览后继续按压后调用此方法(Pop),调用此方法后一般将预览控制器显示出来.
参数:
- previewingContext 预览上下文
- viewControllerToCommit 控制器,就是在上一个代理方法中返回的控制器
code
主控制器的代码实现
- 创建了tableView
- 实现tableView的Peek和Pop
#import "ViewController.h"
#import "DYPreviewingViewController.h"
@interface ViewController () <UITableViewDelegate,UITableViewDataSource,UIViewControllerPreviewingDelegate>
@property (nonatomic, strong) UITableView *tableView;
@property (nonatomic, strong) UIView *soureView;
@end
@implementation ViewController
- (void)viewDidLayoutSubviews {
[super viewDidLayoutSubviews];
CGFloat tableY = CGRectGetMaxY(self.navigationController.navigationBar.frame);
self.tableView.frame = CGRectMake(0,
tableY,
[UIScreen mainScreen].bounds.size.width,
[UIScreen mainScreen].bounds.size.height - tableY);
}
- (void)viewDidLoad {
[super viewDidLoad];
self.automaticallyAdjustsScrollViewInsets = NO;
[self addTableView];
[self addPreview];
}
- (void)addTableView {
self.tableView = [[UITableView alloc] initWithFrame:CGRectZero style:UITableViewStyleGrouped];
self.tableView.delegate = self;
self.tableView.dataSource = self;
self.tableView.rowHeight = 80;
[self.view addSubview:self.tableView];
}
- (void)addPreview {
//判断是否支持3D-Touch
if (self.traitCollection.forceTouchCapability == UIForceTouchCapabilityAvailable) {
//支持就注册代理
[self registerForPreviewingWithDelegate:(id)self sourceView:self.tableView];
} else {
//不支持
NSLog(@"3D Touch is not available on this device.");
}
}
#pragma mark - tableViewDataSource
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
return 2;
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
return 5;
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:@"shortcut"];
if (!cell) {
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:@"shortcut"];
}
cell.textLabel.text = [NSString stringWithFormat:@"第%zd组,第%zd行",indexPath.section,indexPath.row];
cell.accessoryType = UITableViewCellAccessoryDisclosureIndicator;
return cell;
}
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
NSLog(@"选中了%zd组,%zd行",indexPath.section,indexPath.row);
}
#pragma mark - UIViewControllerPreviewingDelegate
- (UIViewController *)previewingContext:(id<UIViewControllerPreviewing>)previewingContext viewControllerForLocation:(CGPoint)location {
NSLog(@"%s", __FUNCTION__);
//控制变模糊的区域
//location = [self.view convertPoint:location toView:self.tableView];
NSLog(@"%@\n%@",previewingContext,NSStringFromCGPoint(location));
NSIndexPath *indexPath = [self.tableView indexPathForRowAtPoint:location];
if (indexPath) {
NSLog(@"%zd",indexPath.row);
CGRect selectedFrame = [self.tableView cellForRowAtIndexPath:indexPath].frame;
//selectedFrame = [self.tableView convertRect:selectedFrame toView:self.view];
//sourceRect是控制选中的区域(不变模糊的区域)
previewingContext.sourceRect = selectedFrame;
}
else {
return nil;
}
DYPreviewingViewController *preview = [[DYPreviewingViewController alloc] init];
return preview;
}
- (void)previewingContext:(id<UIViewControllerPreviewing>)previewingContext commitViewController:(UIViewController *)viewControllerToCommit {
[self showViewController:viewControllerToCommit sender:self];
NSLog(@"viewControllerToCommit = %@ previewingContext = %@", viewControllerToCommit, previewingContext);
}
@end
预览详情控制器的代码实现
- 返回Actions,这样预览的时候,上滑就会出现相应的选项,点击去执行相应的代码.
#import "DYPreviewingViewController.h"
@interface DYPreviewingViewController ()
@property (nonatomic, strong) NSMutableArray *items;
@end
@implementation DYPreviewingViewController
- (void)viewDidLoad {
[super viewDidLoad];
self.automaticallyAdjustsScrollViewInsets = NO;
self.view.backgroundColor = [UIColor redColor];
self.navigationItem.title = @"previewing";
}
#pragma mark - 返回预览选项数组
- (NSArray<id<UIPreviewActionItem>> *)previewActionItems {
UIPreviewAction *action1 = [UIPreviewAction actionWithTitle:@"Action 1"
style:UIPreviewActionStyleDefault
handler:^(UIPreviewAction * _Nonnull action, UIViewController * _Nonnull previewViewController) {
NSLog(@"Action 1 triggered");
}];
UIPreviewAction *action2 = [UIPreviewAction actionWithTitle:@"Action 2"
style:UIPreviewActionStyleSelected
handler:^(UIPreviewAction * _Nonnull action, UIViewController * _Nonnull previewViewController) {
NSLog(@"Action 2 triggered");
}];
UIPreviewAction *action3 = [UIPreviewAction actionWithTitle:@"Action 3"
style:UIPreviewActionStyleDestructive
handler:^(UIPreviewAction * _Nonnull action, UIViewController * _Nonnull previewViewController) {
NSLog(@"Action 3 triggered");
}];
NSMutableArray *actions = [NSMutableArray arrayWithObjects: action1,action2,action3,nil];
return [actions copy];
}
@end