iOS进阶iOS开发iOS的UI进阶

QQ消除小红点(一键退朝)动画。

2016-03-28  本文已影响1925人  AidenRao

本来只是想写个可以拖动的小红点的,但写出乐趣来了,所以就多研究了研究,最后干脆封装了一下,可以实现给所有 View 添加黏贴效果。
GitHub 链接
效果如图:

11-22-34.jpg

一个控制点的取了两次点,才绘制出贝塞尔曲线,所以称为二次曲线,两个控制点的取了三次点,所以称为三次曲线。

绘制贝塞尔曲线有一个数字需要记住,3.6。

三阶贝塞尔曲线拟合1/4圆

即 AB 和 CD 都垂直于 AD,AB 和 CD 的距离为 AB 距离的 1/3.6,绘制出的弧线是一个非常接近 1/4 圆的弧线。

实现思路:
需要绘制黏贴效果
拖动的 View 需要盖住其它所有其它的 View
根据拖动的距离判断松手时是需要爆炸动画还是回弹动画。

效果如下

11-31-30.jpg

转换成模型图如下


11-34-14.jpg

小圆是小红点一开始的位置,大的圆是小红点拖过去的位置,小圆随着拖动距离增大而变大,两个圆的连接其实就是两贝塞尔曲线,临时点 point_temp 根据两个圆距离的增加从 p2 向 p4 移动,连接临时点和 P1 连线中点 P5 就是控制点了,即可绘制出这条贝塞尔曲线,p3 和 p5 之间的贝塞尔曲线同理。

接下来就是计算各个点的坐标了,捡起高中的数学,还是很简单的。得出各个点的坐标,然后绘制一个大圆一个小圆,中间绘制两条贝塞尔曲线,给上填充颜色。黏贴效果就出来了。每次拖动 View 的时候再重新绘制一遍。

11-47-42.jpg


需要让拖动的 View 覆盖在所有 View 上方,这个还是很重要的,要不然在 tableViewCell 里进行拖动的时候,会被其它的 Cell 盖住,我的实现方式是声明一个全屏大小的 RedDotView 添加到 [[[UIApplication sharedApplication].delegate window] 上,然后将拖动的 View 拷贝一份,放置到 RedDotView 上方,隐藏旧 View。这样拖动的 View 就能盖住所有其它的 View ,包括导航栏。

拷贝我取了个巧,直接将旧 View 绘制成一张 image,放置到新 View 上显示,

- (UIImage *)getImageFromView:(UIView *)view {
    UIGraphicsBeginImageContextWithOptions(view.bounds.size, NO, UIScreen.mainScreen.scale);
    [view.layer renderInContext:UIGraphicsGetCurrentContext()];
    UIImage *image = UIGraphicsGetImageFromCurrentImageContext();
    UIGraphicsEndImageContext();
    return image;
}

爆炸效果则是给 imageView 的 animationImages 属性添加六张图片,在超出最大距离之后播放。

    NSMutableArray *array = [[NSMutableArray alloc] init];
    for (int i = 1; i < 6; i++) {
        UIImage *image = [UIImage imageNamed:[NSString stringWithFormat:@"red_dot_image_%d", i]];
        [array addObject:image];
    }
    UIImageView *imageView = [[UIImageView alloc] init];
    imageView.frame = CGRectMake(0, 0, radius*2, radius*2);
    imageView.center = explosionPoint;
    imageView.animationImages = array;
    [imageView setAnimationDuration:0.25];
    [imageView setAnimationRepeatCount:1];
    [imageView startAnimating];
    [self addSubview:imageView];
    ```
    
回弹效果是给 View 一个弹簧动画,让 View 弹回旧 View 中心的位置
```objc
    [UIView animateWithDuration:0.5 delay:0.0 usingSpringWithDamping:0.2 initialSpringVelocity:0.0 options:UIViewAnimationOptionCurveEaseInOut animations:^{
        view.center = point;
    } completion:^(BOOL finished) {
        ......
    }];
    ```
总结:还是有些遗憾,做完之后才注意到 QQ 的实现上,p1 和 p3 连线并不经过圆心,所以效果和 QQ 的还是有些差别,另外为了让中间的贝塞尔曲线不会和大圆重合,中间的贝塞尔曲线我用的是两条贝塞尔曲线实现,这样更圆滑一些,但也留了个坑,中间的弧度还是得再调整一下。

参考资料:
[QQ手机版 5.0“一键下班”设计小结](https://isux.tencent.com/qq-mobile-off-duty.html)
上一篇下一篇

猜你喜欢

热点阅读