前言:做相关demo动画已经有一段时间了、现在闲下来记录下相关动画制作。iOS动画主要就是路径动画、帧动画、缩放动画、以及这些动画的组合叫组合动画。另外还有一些3D动画和转场动画。不想看原理的直接下载demo使用方式很简单。
摇杆(手柄)制作
首先需要绘制摇杆的范围我这画了一个圆形、然后监听用户的手势、根据手势移动的前后位置判断移动的方向上、下、左、右。此外如果你规定用户只能上下或者左右移动、不能斜角移动、你可以根据移动的位置判断当前点和中心点这条直线的斜率偏移不能超过多少度。
效果如下:
1.绘制背景边界圆
CGContextRef context = UIGraphicsGetCurrentContext();
// CGContextSetRGBFillColor (context, 1, 0, 0, 1.0);//设置填充颜色
CGContextSetRGBStrokeColor(context,143/255.0,190/255.0,81/255.0,1.0);//画笔线的颜色
CGContextSetLineWidth(context, 2.0);//线的宽度
bigRadius = LL_mmWidth(self)/2.0-4;
CGContextAddArc(context, LL_mmWidth(self)/2.0, LL_mmHeight(self)/2.0, bigRadius, 0, 2*PI, 0); //添加一个圆
CGContextDrawPath(context, kCGPathStroke); //绘制路径
2.绘制中间摇杆圆和四个方向标志以及添加摇杆手势监听。
-(void)createCenterCircle:(CGRect)selfFrame
{
//中间摇杆圆
_centerView = [[UIView alloc]init];
_centerView.frame = CGRectMake((CGRectGetWidth(selfFrame)-CGRectGetWidth(selfFrame)/3.0)/2.0, (CGRectGetHeight(selfFrame)-CGRectGetHeight(selfFrame)/3.0)/2.0, CGRectGetWidth(selfFrame)/3.0, CGRectGetHeight(selfFrame)/3.0);
_handShankOriginCenter = _centerView.center;
smallRadius = (CGRectGetWidth(selfFrame)/3.0)/2.0;
_centerView.layer.cornerRadius = smallRadius;
_centerView.layer.masksToBounds = YES;
_centerView.alpha = 0.8;
_centerView.backgroundColor = [UIColor colorWithRed:143/255.0 green:190/255.0 blue:81/255.0 alpha:1.0];
[self addSubview:_centerView];
//四个方向标志
float interval = (CGRectGetHeight(selfFrame)-LL_mmHeight(_centerView))/4.0;
for (int i = 0; i<4; i++) {
UIImageView *arrow = [self InsertImageView:self cgrect:CGRectMake(0, 0, 20*FIT_WIDTH, 12*FIT_WIDTH) image:[UIImage imageNamed:self.handShankArrows[i]]];
// InsertImageView(self, CGRectMake(0, 0, 20*FIT_WIDTH, 12*FIT_WIDTH), [UIImage imageNamed:self.handShankArrows[i]]);
// arrow.hidden = YES;//注意隐藏箭头了
switch (i) {
case 0:
{
//上
arrow.center = CGPointMake(CGRectGetWidth(selfFrame)/2.0, interval);
}
break;
case 1:
//下
arrow.center = CGPointMake(CGRectGetWidth(selfFrame)/2.0, CGRectGetHeight(selfFrame)-interval);
break;
case 2:
//左
arrow.frame = CGRectMake(0, 0, 12*FIT_WIDTH, 20*FIT_WIDTH);
arrow.center = CGPointMake(interval, CGRectGetHeight(selfFrame)/2.0);
break;
case 3:
//右
arrow.frame = CGRectMake(0, 0, 12*FIT_WIDTH, 20*FIT_WIDTH);
arrow.center = CGPointMake(CGRectGetWidth(selfFrame)-interval, CGRectGetHeight(selfFrame)/2.0);
break;
default:
break;
}
}
//摇杆添加移动手势
UIPanGestureRecognizer *pangesture = [[UIPanGestureRecognizer alloc]initWithTarget:self action:@selector(pangestureAction:)];
[_centerView addGestureRecognizer:pangesture];
}
3.分析手势数据根据上一次移动的点和这次的做比较判断移动方向
-(void)pangestureAction:(UIPanGestureRecognizer *)recognizer
{
CGPoint translation = [recognizer translationInView:self];
[recognizer setTranslation:CGPointZero inView:self];
CGPoint movingPosition = CGPointMake(recognizer.view.center.x + translation.x,
recognizer.view.center.y + translation.y);
int rangeRadius = bigRadius - smallRadius;
if ([self isInciclelPoint:movingPosition andR:rangeRadius centrePoing:_handShankOriginCenter]) {
_lasrtPoint = movingPosition;
_centerView.center = _lasrtPoint;
if (_lasrtPoint.y < _startPoint.y && (fabsf((float)(_lasrtPoint.y - _startPoint.y)) > fabs(_lasrtPoint.x - _startPoint.x))) {
//上
if (_currentDirection == HandShankDirectionUnknow) {
NSLog(@"开始上");
_currentDirection = HandShankDirectionStartTop;
}else{
NSLog(@"上");
_currentDirection = HandShankDirectionTop;
}
}else if (_lasrtPoint.y > _startPoint.y && (fabsf((float)(_lasrtPoint.y - _startPoint.y)) > fabs(_lasrtPoint.x - _startPoint.x)))
{
if (_currentDirection == HandShankDirectionUnknow) {
NSLog(@"开始下");
_currentDirection = HandShankDirectionStartDown;
}else{
NSLog(@"下");
_currentDirection = HandShankDirectionDown;
}
}else if (_lasrtPoint.x >_startPoint.x && (fabsf((float)(_lasrtPoint.x -_startPoint.x)) > fabsf((float)(_lasrtPoint.y -_lasrtPoint.y))) )
{
if (_currentDirection == HandShankDirectionUnknow) {
NSLog(@"开始右");
_currentDirection = HandShankDirectionStartRight;
}else{
NSLog(@"右");
_currentDirection = HandShankDirectionRight;
}
}else if (_lasrtPoint.x <_startPoint.x && (fabsf((float)(_lasrtPoint.x -_startPoint.x)) > fabsf((float)(_lasrtPoint.y -_lasrtPoint.y))) )
{
if (_currentDirection == HandShankDirectionUnknow) {
NSLog(@"开始左");
_currentDirection = HandShankDirectionStartLeft;
}else{
NSLog(@"左");
_currentDirection = HandShankDirectionLeft;
}
}
if (self.delegete && [self.delegete respondsToSelector:@selector(handShankDirectionDidChange:)]) {
[self.delegete handShankDirectionDidChange:_currentDirection];
}
}
if(recognizer.state == UIGestureRecognizerStateEnded || recognizer.state == UIGestureRecognizerStateCancelled || recognizer.state == UIGestureRecognizerStateFailed)
{
NSLog(@"结束");
_startPoint = _handShankOriginCenter;
[UIView animateWithDuration:0.5 animations:^{
_centerView.center = _handShankOriginCenter;
}];
_currentDirection = HandShankDirectionUnknow;
if (self.delegete && [self.delegete respondsToSelector:@selector(handShankDirectionDidEnd)]) {
[self.delegete handShankDirectionDidEnd];
}
}
}
饼状图绘制
前言:饼状图由三角弧组成、弧线有起始角度和末尾角度组成、所以可以用一个mode类记录相关信息。然后绘制三角弧。效果如下:
1.弧线贝塞尔路径写法
-(UIBezierPath *)bezierPathStartAngle:(CGFloat)startAngle endAngle:(CGFloat)endAngle
{
UIBezierPath *path = [UIBezierPath new];
[path moveToPoint:_centerPoint];
[path addArcWithCenter:_centerPoint radius:_radius startAngle:DEGREES_TO_RADIANS(startAngle) endAngle:DEGREES_TO_RADIANS(endAngle) clockwise:YES];
[path closePath];
return path;
}
2.生成弧线和对应的文字
-(void)createPieChartView
{
[self.models enumerateObjectsUsingBlock:^(CurveModel * _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) {
UIBezierPath *path = [self bezierPathStartAngle:obj.startAngel endAngle:obj.endAngel];
CAShapeLayer *trangleLayer = [CAShapeLayer layer];
// maskLayer.backgroundColor = [UIColor purpleColor].CGColor;
trangleLayer.path = [path CGPath];
trangleLayer.fillColor = obj.color.CGColor;
trangleLayer.fillRule = kCAFillRuleNonZero;//kCAFillRuleEvenOdd画的区域 取反 解释为奇偶。
[self.layer addSublayer:trangleLayer];
obj.trangleLayer = trangleLayer;
CGFloat angle = obj.endAngel-(obj.endAngel-obj.startAngel)/2.0;//扇形边缘中心位置的角度
//扇形边缘的中心点
// CGPoint aPoint = CGPointMake(_centerPoint.x+ _radius*cos(DEGREES_TO_RADIANS(angle)),_centerPoint.y+ _radius*sin(DEGREES_TO_RADIANS(angle)));
//外面边缘的半径
CGFloat outRadius = [self height]/2.0+100;//100是随意
CGPoint outCenterPoint = CGPointMake(_centerPoint.x+ outRadius*cos(DEGREES_TO_RADIANS(angle)), _centerPoint.y+outRadius*sin(DEGREES_TO_RADIANS(angle)));
obj.outCenterPoint = outCenterPoint;
int width = 30;
//内部边缘文字
UILabel *label0 = [[UILabel alloc]init];
label0.adjustsFontSizeToFitWidth = YES;
label0.bounds = CGRectMake(0, 0, width, width);
CGFloat newRadius0 = (_radius-((width/2.0)/cos(DEGREES_TO_RADIANS(45))));//扇形的半径+label的对角线长度
//新半径扇形的边缘中心点
CGPoint bPoint0 = CGPointMake(_centerPoint.x+ newRadius0*cos(DEGREES_TO_RADIANS(angle)), _centerPoint.y+newRadius0*sin(DEGREES_TO_RADIANS(angle)));
obj.innerLabelCenterPoint = bPoint0;
obj.innerLabe = label0;
label0.center = outCenterPoint;
label0.text = @"6";
label0.textAlignment = NSTextAlignmentCenter;
[self addSubview:label0];
//外围边缘文字
UILabel *label = [[UILabel alloc]init];
label.text = @"%10";
label.textAlignment = NSTextAlignmentCenter;
label.adjustsFontSizeToFitWidth = YES;
label.bounds = CGRectMake(0, 0, width, width);
CGFloat newRadius = (_radius+((width/2.0)/cos(DEGREES_TO_RADIANS(45))));//扇形的半径+label的对角线长度
//新半径扇形的边缘中心点
CGPoint bPoint = CGPointMake(_centerPoint.x+ newRadius*cos(DEGREES_TO_RADIANS(angle)), _centerPoint.y+newRadius*sin(DEGREES_TO_RADIANS(angle)));
obj.outLabelCenterPoint = bPoint;
obj.outLabel=label;
label.center = outCenterPoint; //CGPointMake( aPoint.x+width/2.0, aPoint.y+((width/2.0)*tan(DEGREES_TO_RADIANS(angle))));
[self addSubview:label];
}];
}
3.添加简单翻转动画和路径动画
-(void)startAnimation
{
//翻转 oglFlip
[CommonUse addAnimationLayer:self.layer type:@"oglFlip"];
[self.models enumerateObjectsUsingBlock:^(CurveModel * _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) {
[self startLabelAnimation:obj];
}];
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(2.1 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
[self stopAnimation];
});
}
传送门:
源码
有疑问的小伙伴欢迎加交流讨论QQ:206931384