前段时间花了点时间去研究了3DTouch这一块,咱们就来聊一下,看看怎么在app中集成3DTouch中peek pop。 虽说iOS9出了这个功能感觉不太实用,但是作为一个开发者,我觉得还是有必要去了解一下,弄好了还能让自己的app装一回逼。那下面简单介绍一下peek和pop分别是什么。
peek:当你用力按下屏幕按到一定程度时,系统会弹出一个预览视图,这个过程就称之为peek。
pop:再用力按下去就会展开到预览视图的控制器,这过程就是pop。
废话不多说,直接上代码
1、在viewDidLoad方法中注册预览代理
// 注意这是ios9的API,需要做一下版本控制,否则运行到9以下的会崩。
#ifdef __IPHONE_9_0
if(KC_IS_IOS9) {
// 判断设备是否支持3dTouch
if(self.traitCollection.forceTouchCapability == UIForceTouchCapabilityAvailable) {
[selfregisterForPreviewingWithDelegate:self sourceView:self.view];
}
}
#endif
2、注册完成后控制器需要遵守<UIViewControllerPreviewingDelegate>此协议,那我们来看看协议内定义的方法。
NS_CLASS_AVAILABLE_IOS(9_0)@protocolUIViewControllerPreviewingDelegate
// If you return nil, a preview presentation will not be performed
// peek过程会调用此方法,返回需要预览的控制器(即需要跳转到下一级的控制器)
- (nullableUIViewController*)previewingContext:(id)previewingContext viewControllerForLocation:(CGPoint)locationNS_AVAILABLE_IOS(9_0);
// pop过程会调用此方法,执行跳转
- (void)previewingContext:(id)previewingContext commitViewController:(UIViewController*)viewControllerToCommitNS_AVAILABLE_IOS(9_0);
@end
协议中两个方法是require的,所以控制器必须要实现这两个方法,那该在这两个方法干些什么呢?我们来实现协议中的方法吧。
#pragma mark -UIViewControllerPreviewingDelegate
// Peek
- (UIViewController*)previewingContext:(id)context viewControllerForLocation:(CGPoint) point
{
/*
context: 执行peek的上下文对象。
point: 按压位置再souceView上的点,可以理解为手指在屏幕上的按压点。
*/
// 1、获取sourceView 即注册时传入的sourceView,一般为控制器的view
UIView*sourceView = [context sourceView];
// 然后判断按压点是否在某个控件的frame内,假设我们有某个自定义控件为self.locationView
/*
这里有个涉及到坐标系转换的细节问题
如果self.locationView不是sourceView的直接子控件,那么我们需要把point转换到self.locationView的父控件的坐标系中,代码如下:
point = [self.locationView.superView convertPoint:point fromView:sourceView];
若缺少这段代码,你会发现按压位置错乱的bug。
*/
// 2、如果self.locationView.frame不包含这个点就直接return,不做任何操作
if(!CGRectContainsPoint(self.locationView.frame, point)) return nil;
// 能来到这里,即触摸点在self.locationView上,那么
// 3、设置sourceRect,这个souceRect就是当你按压时候浮起来的那个矩形区域
CGRect sourceRect = self.locationView.frame;
/*
如果self.locationView不是sourceView的直接子控件,这里同时也涉及到坐标系转换
sourceRect = [self convertRect:self.locationView.frame toView:sourceView];
*/
[context setSourceRect:sourceRect];
// 4、然后创建需要跳转的目标控制器返回就OK了
MyLocationViewController*locationVC = [MyLocationViewController new];
// 目标控制器有参数也需要传入参数
locationVC.locationModel=self.locationModel;
return locationVC;
}
// pop
- (void)previewingContext:(id)previewingContext commitViewController:(UIViewController*)viewControllerToCommit {
// 这里十分简单,只需要直接show一下就OK了
[self showViewController:viewController ToCommitsender:self];
}
3、peek,pop这么简单就实现了,下面我们再来看看怎么在tableView中使用
- (UIViewController*)previewingContext:(id)context viewControllerForLocation:(CGPoint) point
{
// 1、获取sourceView
UIView*sourceView = [context sourceView];
/**通过坐标点获取 indexPath */
/*
同样如果sourceView != self.tableView的话,也需要转换坐标系
point = [self.tableView convertPoint:point fromView:sourceView];
*/
NSIndexPath*indexPath = [self.tableView indexPathForRowAtPoint:point];
// 如果indexPath为nil,则直接返回nil
if(!indexPath) return nil;
/**获得当前cell */
HCQBusinessCell*cell = [self.tableView cellForRowAtIndexPath:indexPath];
// 设置sourceRect
CGRect sourceRect = cell.frame;
/*
这里同时也涉及到坐标系转换
sourceRect = [self.tableView convertRect:cell.frame toView:sourceView];
*/
[context setSourceRect:sourceRect];
HCQMechantDetailViewController*detailVC = [HCQMechantDetailViewController new];
detailVC.mechantModel= cell.mechantModel;
returndetailVC;
}
4、至此,在tableView上Peek,pop也集成完毕,至于collectionView也是类似,我就不多说了。然而我在网上看到一些文章,他们是把注册放到cellForRow方法中,类似这样子:
- (UITableViewCell*)tableView:(UITableView*)tableView cellForRowAtIndexPath:(NSIndexPath*)indexPath
{
HCQBusinessCell*cell = [tableViewdequeueReusableCellWithIdentifier:HCQBusinessCellReuseID];
cell.mechantModel=self.mechantModels[indexPath.row];
// 3DTouch peek..pop
if(KC_IS_IOS9) {
if(self.traitCollection.forceTouchCapability == UIForceTouchCapabilityAvailable) {
[self registerForPreviewingWithDelegate:self sourceView:cell];
}
}
returncell;
}
我只想说:大家千万不要这样搞,代理只需要注册一次,重复注册就会有问题了。有兴趣的可以自行尝试,但我真不建议你这样做。好了,先说这么多吧,快点为你的app集成3DTouch,开展你的装B之旅吧~~