美文网首页swift编程开发iosiOS
关于3DTouch中Peek与Pop的正确使用

关于3DTouch中Peek与Pop的正确使用

作者: _Erica | 来源:发表于2016-07-29 10:46 被阅读1561次

    前段时间花了点时间去研究了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之旅吧~~

    相关文章

      网友评论

      • 床前明月_光:我想问
        if(self.traitCollection.forceTouchCapability == UIForceTouchCapabilityAvailable) {
        [self registerForPreviewingWithDelegate:self sourceView:cell];
        }
        }

        这样子会有什么问题? 你文章所说的注册代理方法, 很明显peek的时候跟注册cell的时候的UI效果很不一样.

      本文标题:关于3DTouch中Peek与Pop的正确使用

      本文链接:https://www.haomeiwen.com/subject/jukzjttx.html