在推酷安卓客户端看到的这种效果,发现iOS端没有这种点击的动效,就随手研究了下。

先看效果

分为三种效果:

  • 单击
  • 单击长按并滑动手指
  • 单击长按滑动tableview

demo
demo

思路

思路一

过程

在tableviewcell的contentview里面添加两个手势,一个UITapGestureRecognizer和一个UILongPressGestureRecognizer来获取当前点击是单击还是长按操作,方便的是如果是长按操作,那么在一个方法里面就可以捕捉整个长按的过程:

/**
 *  处理长按手势
 *
 *  @param longPressGestureRecognizer 长按手势
 */
- (void)handleLongPressGestures:(UILongPressGestureRecognizer *)longPressGestureRecognizer
{
    if (longPressGestureRecognizer.state == UIGestureRecognizerStateBegan) {
        //长按开始.......
        //开始慢速动画
    }
    if((longPressGestureRecognizer.state == UIGestureRecognizerStateEnded || longPressGestureRecognizer.state == UIGestureRecognizerStateCancelled))
    {
      //长按结束和取消.....
      //如果动画结束,直接移除layer
      //如果动画没有结束,继续加速动画
    }
    if (longPressGestureRecognizer.state == UIGestureRecognizerStateChanged) {
       //长按状态改变,手指滑动.....
       //用[longPressGestureRecognizer locationInView:self]返回的CGPoint判断手指是在移到cell外部,加速动画至结束后移除
}

这里配合着给layer添加的animation的delegate使用,来判断动画是否在进行或者结束。

问题

我先是在view上做效果,效果完成后改用自定义的cell调试,这时候发现了问题: 使用了自定义cell的tableview的didSelectRowAtIndexPath这个代理方法不会调用。研究发现原来是我添加的两个手势和系统的select手势操作发生了冲突。导致那两个手势把系统手势拦截了下来,该方法不执行。那么该怎么解决这个问题呢? 我发现了这个方法:

- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldReceiveTouch:(UITouch *)touch
{
        //假如自定义添加了两个手势,那么该方法会调用三次,其中包括一次系统手势
        //gestureRecognizer 返回的手势
        // touch 接受的touch点击
        //返回值代表是否拦截事件
}

在这个方法里面就可以做判断,如果是系统手势,就不拦截。如果是自定义手势,则拦截。

思路二

利用系统提供的touchesBegan,touchesMoved,touchesEnded,touchesCancelled四个方法进行逻辑判断提供动画效果。 因为我要在touchesBegan这个方法里面判断是单击还是长按,来分别做快速和慢速动画,所以这里用了个小技巧,就是用延迟0.1秒touchCancelledOrEnded做动画。

-(void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event
{
    [super touchesBegan:touches withEvent:event];
    _touchCancelledOrEnded = NO;
        excute_block_after(0.1f, ^{
            [self creatAnimation];
    });
}
- (void)touchesEnded:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event
{
    [super touchesEnded:touches withEvent:event];
    _touchCancelledOrEnded = YES;
}
- (void)touchesCancelled:(NSSet *)touches withEvent:(UIEvent *)event
{
    [super touchesCancelled:touches withEvent:event];
    _touchCancelledOrEnded = YES;
}

- (void)creatAnimation
{
    if(_touchCancelledOrEnded == YES)
    {
        //快速动画
    }else
    {
        //快速动画
    }
}

具体过程请看代码。

待解决的问题

事实上,这个效果目前还不够完善。比如说在didSelectRowAtIndexPath这个tableview代理里面填写代码在点击cell的时候跳转到另一个控制器。上面的演示demo也可以看出,单击的时候由于控制器之间的跳转太快,导致阴影动画看不清楚。最理想的状态是:在自定义cell内部拦截这个select事件,等到cell的动画结束后,再通知tableview的didSelectRowAtIndexPath方法执行响应的控制器跳转代码。为了方便其他人使用,我应该在cell内部完成整个拦截和通知过程。 我曾在stackoverflow上查找相关问题无果后,问了这个问题,希望有人知道的话,能给我一个思路,我将非常感激您并完善它。

GitHub地址:点击这里