关于QQ消息小圆点粘性动画原理剖析待续。。。。

感谢网络分享   http://www.tuicool.com/articles/aaimAjE

先来看下面的这幅图片:如果数学几何不好的可以好好补习一下;

关于QQ消息小圆点粘性动画原理剖析待续。。。。_第1张图片

----------------------------------下面的内容是我从网上粘贴的一段话,主要是说了,我们可以在两个圆的之间重新绘制两条直线和两条贝塞尔曲线  ,没那么深奥;但是他说没用到draweRect 方法用了CAShapeLayer 好像在哪儿见过,

---------------------------------------------来自网络分享

可以利用Core Graphics在drawRect方法里面绘制不规则矩形的path,然后利用颜色fill就行。不规则矩形是随着大圆的移动而不断变化的,如果在drawRect方法里面绘制,那么在移动过程中不断调用setNeedsDisplay方法进行重绘。这是种可行的方案,我所用的也大致是这种思路。

不过,我没有在drawRect方法里面绘制,而是利用了CAShapeLayer,将不规则矩形的path绘制在shapeLayer里面,这样在移动大圆的过程中不断更新CAShapeLayer的path即可。

---------------------------------------------

//关于CAShapeLayer 的解释

关于QQ消息小圆点粘性动画原理剖析待续。。。。_第2张图片
来自我的百度网盘    http://pan.baidu.com/s/1eRPBaq2

首先我们先假设两个圆都存在来绘制一个贝塞尔曲线    UIBezierPath   只要我们拿到曲线我们就可以渲染出来图形了,而且跟着两个View【 bigView  and  smallView 的位置的变化而变化 】

- (UIBezierPath*)pathWithBigCircleView:(UIView *)bigCircleView  smallCircleView:(UIView  *)smallCircleView

CGPoint  bigCenter = bigCircleView.center;  //得到大圆View 的中心点;

CGFloat x2 = bigCenter.x; //获得大圆的中心点坐标X

CGFloat y2 = bigCenter.y;    //获得大圆的中心点坐标Y

CGFloat r2 = bigCircleView.bounds.size.width /2;//大圆的半径

CGPoint smallCenter = smallCircleView.center;//小圆就不解释了同大圆   

CGFloat x1 = smallCenter.x;   

 CGFloat y1 = smallCenter.y;    

CGFloat r1 = smallCircleView.bounds.size.width /2;

//获取圆心距离


关于QQ消息小圆点粘性动画原理剖析待续。。。。_第3张图片
求两点之间的距离目的: 

//调用下面的方法来求两点间的距离;?? 是不是不知道为什么要求他,先向下看后面会用到他求一些数据;用来求下面的黄色的角度的根据几何知识了解证明出一些相等的角度以及相应的cosθ 弧度数值和 sinθ 弧度数值

CGFloat   d = [self     distanceWithPointA:bigCenter pointB:smallCenter];  

//Θ:(xita)    


关于QQ消息小圆点粘性动画原理剖析待续。。。。_第4张图片
关于  θ 角度的计算 图中已经写出来了,我是普及一下数学知识

  CGFloat   sinθ = (x2 - x1) / d; //等于图中的  L/d;


//坐标系基于父控件

CGPoint pointA = CGPointMake(x1 - r1 *cosθ , y1 + r1 *sinθ);//A点是小圆和大圆的公切线和小圆的交点A

CGPoint pointB = CGPointMake(x1 + r1 *cosθ , y1 - r1 *sinθ);//B点是小圆和大圆的公切线和小圆的交点B,是下面的公切线;

CGPoint pointC = CGPointMake(x2 + r2 *cosθ , y2 - r2 *sinθ);    //小圆和大圆的公切线和小圆的交点

CGPoint pointD = CGPointMake(x2 - r2 *cosθ , y2 + r2 *sinθ);  //小圆和大圆的公切线和小圆的交点

 CGPoint pointO = CGPointMake(pointA.x+ d /2*sinθ , pointA.y+ d /2*cosθ);  //点O是和点P 是平行两边的直线并垂直于两圆心的距离,然后和两圆心d的中点相交

  CGPoint pointP =  CGPointMake(pointB.x+ d /2*sinθ , pointB.y+ d /2*cosθ);        

UIBezierPath*path= [UIBezierPath bezierPath]; //创建贝塞尔曲线

//A    [path moveToPoint:pointA];  //绘制A--B 的直线

//AB   

 [path addLineToPoint:pointB]; 

//绘制BC曲线   

 [path addQuadCurveToPoint:pointC controlPoint:pointP];  //给path 添加 点C  以及点B--C 的控制点  P 

//CD   

 [path addLineToPoint:pointD];  //连接C----D

//绘制DA曲线    

[path addQuadCurveToPoint:pointA controlPoint:pointO];  //绘制 D--A的曲线  控制点为点O   到此绘制曲线结束

return  path;

}

}

**************求两点的距离

- (CGFloat)distanceWithPointA:(CGPoint)pointApointB:(CGPoint)pointB

{

//这个方法是求两点之间的距离的

CGFloat dx = pointB.x - pointA.x;

CGFloat dy = pointB.y - pointA.y;

return  sqrt (dx * dx + dy * dy);  //开方的算法    (dx^2+dy^2)   再开方   算出两点之间距离; 

}


在实现过程中,我是自定义UIButton的,需要注意的是,在监听button的拖动时,最好是给它添加UIPanGestureRecognizer手势,而不要在touchesBegin方法里面去判断它的移动位置,因为Touches系列方法会屏蔽button的点击。

自定义的这个button默认就是大圆,包含一个小圆(UIView)属性,但是这个小圆并不是添加在自定义的这个button(也就是大圆)里面,而是在button的superView上。因为小圆并不需要随着大圆位置的改变而改变位置,相应的,shapeLayer也是添加在button(大圆)的父控件上。

给大圆添加了pan手势,在pan:方法里面随之改变小圆的大小和绘制shapeLayer的path。

当pan手势状态为End的时候,需要判断大圆与小圆的距离有没有超出最大距离,如果超过,那么添加一个gif图片,播放销毁大圆的过程。如果没有被销毁,那么大圆需要复位,相应代码:

//下面我就直接粘代码了

#import "ZYGooView.h"

#define kMaxDistance 100

@interfaceZYGooView()

@property(nonatomic, weak)UIView*smallCircleView; 

@property(nonatomic, assign)CGFloat  smallCircleR;

@property(nonatomic, weak)CAShapeLayer*shapeLayer;

@end

@implementationZYGooView

- (instancetype)initWithFrame:(CGRect)frame

{

if(self= [superinitWithFrame:frame]) 

{

        [selfcommitInit];            

}

returnself;

}

- (void)awakeFromNib{ 

   [selfcommitInit];

}

- (void)commitInit

{

self.layer.cornerRadius =self.frame.size.width *0.5;

self.layer.masksToBounds =YES;

self.smallCircleR =self.frame.size.width *0.5;

self.smallCircleView.bounds =self.bounds;

self.smallCircleView.center =self.center;

self.smallCircleView.layer.cornerRadius =self.smallCircleView.frame.size.width *0.5;       

 [self  addGesture];

}

#pragma mark ----懒加载方法

- (UIView*)smallCircleView

{

if(_smallCircleView ==nil)

 {

UIView*view = [[UIViewalloc] init];            

  view.backgroundColor =self.backgroundColor;               

 [self.superviewaddSubview:view];               

 [self.superviewinsertSubview:viewatIndex:0];                

_smallCircleView = view;            

}

return   _smallCircleView;

}

- (CAShapeLayer*)shapeLayer

{

if(_shapeLayer ==nil) 

{

CAShapeLayer*shapeLayer = [CAShapeLayer  layer];        

shapeLayer.path = [self    pathWithBigCircleView:self   smallCircleView:self.smallCircleView].CGPath;        shapeLayer.fillColor =self.backgroundColor.CGColor;                

[self.superview.layer addSublayer:shapeLayer];              

  [self.superview.layer insertSublayer:shapeLayer atIndex:0];              

  _shapeLayer = shapeLayer;   

 }

return  _shapeLayer;

}

#pragma mark ----其他方法

- (void)addGesture

{         //添加手势

UIPanGestureRecognizer*recognizer = [[UIPanGestureRecognizer alloc]initWithTarget:self action:@selector(pan:)];    [self  addGestureRecognizer:recognizer];

}

你可能感兴趣的:(关于QQ消息小圆点粘性动画原理剖析待续。。。。)