频道栏目
首页 > 资讯 > IOS > 正文

iOS旋钮动画-CircleKnob

17-02-28        来源:[db:作者]  
收藏   我要投稿

前段时间和群里的一个设计师配合,根据网上的一个旋钮gif为原型,用代码做出来了。先来看下原型的效果

 

原型效果

 

在看下下面是我做完后成品的效果,加了一个通过移动光源来对阴影控制的效果,这样看起来更立体点。(那个太阳有点不协调。。。)

同时附上代码链接https://git.oschina.net/BearXR/CircleKnob

还有单独的下载包http://download.csdn.net/detail/xiongbaoxr/9419655

 

成品效果

 

下面开始简单的讲解下构思步骤和部分代码片段

1,构建底盘

首先我们要构造两个圆盘和旋钮上的红点

 

这里写图片描述

 

用view画两个圆盘,和一个小的红色控制点。

注意:红色的控制点我又单独新建了一个view,这样方便待会做手势控制,从而不会影响到后面的view。而且所有view的圆心都要设置好。后面和角度相关的处理会很多的。最好能准确和self.view或者window能有直接的关联。

2,底盘增加点击和拖动的手势

在这里我们要增加手势,还有起始点,终点的角度。我画了辅助线,便于调试。手势和过渡效果都写好了。所以效果我就直接放上来了。

 

旋钮动画

 

3,增加外围的扇环

由于后面要做阴影,所以除了扇环的底色和效果是用了一个view,其余的每个小格子我都是新开了一个view,并且将旋钮的圆心位置设置为锚点进行旋转。

 

带有扇环
#pragma mark - 设置外围的扇环形

- (void)initSetFanView

{

CGFloat delta_distance = 26;

fanView = [[FanView alloc] initWithFrame:CGRectMake(0, 0, knob_width + delta_distance * 2, knob_width + delta_distance * 2)];

fanView.center = knob.center;

fanView.backgroundColor = [UIColor clearColor];

fanView.userInteractionEnabled = NO;

[self.view addSubview:fanView];

fanView.knobValue = -startAngleValue;//设置起始点

fanView.lightSource_InWindow = lightSource;

}

- (void)drawRect:(CGRect)rect

{

contextBack = UIGraphicsGetCurrentContext();

contextFore = UIGraphicsGetCurrentContext();

[self drawFan:contextBack

bezierPath:bezierPathBack

knobAngle:180 + endAngleValue

strokeColor:[UIColor colorWithRed:202/255.0 green:207/255.0 blue:202/255.0 alpha:1.0f]];

[self drawFan:contextFore

bezierPath:bezierPathFore

knobAngle:_knobValue

strokeColor:[UIColor colorWithRed:174/255.0 green:0/255.0 blue:0/255.0 alpha:1.0f]];

}

// 绘制扇形

- (void)drawFan:(CGContextRef)context bezierPath:(UIBezierPath *)bezierPath knobAngle:(CGFloat)knobAngle strokeColor:(UIColor *)strokeColor

{

CGRect frame = self.frame;

CGFloat radius = (CGRectGetWidth(frame) - lineWidth) / 2;

CGFloat angleForOne = M_PI / 180.0f;

CGFloat circleLength = radius * 2 * M_PI;

int gapCount = fanShowCount - 1; //间隙个数

CGFloat gapWidth = 5; //间隙距离

// 计算需要绘制的角度(角度制)

knobAngle = knobAngle < -startAngleValue ? -startAngleValue : knobAngle;

knobAngle = knobAngle > 180 + endAngleValue ? 180 + endAngleValue : knobAngle;

// 设置弧线路径

bezierPath = [UIBezierPath bezierPathWithArcCenter:CGPointMake(CGRectGetWidth(frame)/2, CGRectGetHeight(frame)/2) radius:(CGRectGetWidth(frame) - lineWidth)/2.0 startAngle:angleForOne * (180 - startAngleValue) endAngle:angleForOne * (180 + knobAngle) clockwise:YES];

CGContextAddPath(context, bezierPath.CGPath);

// 设置线的颜色,线宽,接头样式

CGContextSetStrokeColorWithColor(context, strokeColor.CGColor);

CGContextSetFillColorWithColor(context, [UIColor clearColor].CGColor);

CGContextSetLineWidth(context, lineWidth);

CGContextSetLineCap(context, kCGLineCapButt);

// 绘制虚线

CGFloat drawLineLength = circleLength * (1- (startAngleValue + endAngleValue)/fullAngleValue);

CGFloat showLineLengthPer = (drawLineLength - gapWidth * gapCount)/(fanShowCount - 1);

CGFloat lengths[2] = {showLineLengthPer,gapWidth};

CGContextSetLineDash(context, 0, lengths, 2);

CGContextDrawPath(context, kCGPathFillStroke);//最后一个参数是填充类型

if (!self.blockViewArray) {

self.blockViewArray = [[NSMutableArray alloc] init];

}

// 绘制小方格view(并且只绘制一次)

static BOOL drawBlock = NO;

if (!drawBlock) {

drawBlock = YES;

for (int i = 1; i < fanShowCount; i++) {

CGFloat blockWidth = lineWidth + 8;

CGFloat blockHeight = 5;

CGFloat block_x = CGRectGetWidth(frame) / 2 - radius - blockWidth/2;

CGFloat block_y = CGRectGetHeight(frame) / 2;

// 角度修正

if (blockHeight > gapWidth) {

block_y = block_y - blockHeight/2;

}else{

block_y = block_y + (gapWidth - blockHeight)/2;

}

// 方格view 可辅助绘制垂直平分线

ViewWithAutoShadow *viewBlock = [[ViewWithAutoShadow alloc] initWithFrame:CGRectMake(block_x, block_y, blockWidth, blockHeight)];

viewBlock.showAssistPoint = NO;

viewBlock.backgroundColor = [UIColor colorWithRed:248/255.0 green:238/255.0 blue:237/255.0 alpha:1.0f];

[self addSubview:viewBlock];

// 根据锚点旋转

CGFloat blockAngle = (180 + startAngleValue + endAngleValue)/fanShowCount*i - startAngleValue;

CGAffineTransform rotate = GetCGAffineTransformRotateAroundPoint1(viewBlock.center.x, viewBlock.center.y, CGRectGetWidth(frame)/2, CGRectGetHeight(frame)/2, blockAngle/180.0 * M_PI);

[viewBlock setTransform:rotate];

AppDelegate *myDelegate = [[UIApplication sharedApplication] delegate];

[viewBlock drawShadowEffectWithSourcePoint:_lightSource_InWindow assistInView:myDelegate.window];

[self.blockViewArray addObject:viewBlock];

}

}

}

4,增加动画效果

给底盘和扇环都增加动效,里面用了定时器。关于定时器可以看参考这篇博客http://blog.csdn.net/xiongbaoxr/article/details/50580701

 

旋钮动效

 

动效的代码片段

// 执行动画

- (void)changeRadiusWithAnimation:(CGFloat)radius lastRadius:(CGFloat)lastRadius duration:(CGFloat)duration

{

CGFloat countAll = ABS(radius - lastRadius);

double delaySeconds = 0.001f;

CGFloat animateCount = duration/delaySeconds;

__block int i = 0;

dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);

dispatch_source_t timer = dispatch_source_create(DISPATCH_SOURCE_TYPE_TIMER, 0, 0, queue);

dispatch_source_set_timer(timer, DISPATCH_TIME_NOW, delaySeconds * NSEC_PER_SEC, 0);

dispatch_source_set_event_handler(timer, ^{

dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{

if (i >= animateCount) {

dispatch_source_cancel(timer);

}else{

i ++;

dispatch_sync(dispatch_get_main_queue(), ^{

// 扇环进度条动画

CGFloat anglePer = countAll/animateCount * i;

int k = radius > lastRadius ? anglePer : -anglePer;

CGFloat needValue = lastRadius + k;

fanView.knobValue = needValue;

// 该方法会重新调用drawRect方法

[fanView setNeedsDisplay];

// 旋钮转动

knob.transform = CGAffineTransformMakeRotation((needValue/180.0 - 0) * M_PI);

});

}

});

});

dispatch_resume(timer);

}

5,最后一步是处理阴影效果,里面涉及的东西比较多。不详细解释代码,说一下思路。关于阴影处理的主要是这个类 ViewWithAutoShadow.h

5.1,首先我们设置一个光源点,这个小太阳就是我们的光源所在的位置

 

设置光源

 

5.2,为了便于调试和理解,我对所有需要做投影效果的view画出了其与光源的连线,view的垂直平分线。并且进行了相应的延长。

同时也把view的四个顶点和中心点也描出来了

 

和光源连接的辅助线

 

5.3,注意看,每个夹脚处都有一个小的出头部分,这就是阴影的偏移量。按照这个偏移量来设置阴影就会有一种仿真的效果。

 

连线细节

 

5.4,我们把阴影效果设置上去看下最终的效果,是不是开始有点感觉了?

 

阴影调试效果

 

5.5最后把所有的辅助线都关掉,再看看效果

 

最终效果
相关TAG标签
上一篇:Moya源码解析
下一篇:手把手教你搞懂 Android 反编译
相关文章
图文推荐

关于我们 | 联系我们 | 广告服务 | 投资合作 | 版权申明 | 在线帮助 | 网站地图 | 作品发布 | Vip技术培训 | 举报中心

版权所有: 红黑联盟--致力于做实用的IT技术学习网站