最近遇到了好多人问我会不会Swift,虽然我很早就进行了Swift的学习,但是苹果对于Swift的更新真是日新月异,和我当时beta版本学习的时候大大不同了,所以,从今天起准备督促自己进行每日一练。
今天想要做的是一个360度的圆型滑动条。
预览效果
细节方面还有欠缺,比如,没有进行旋转圈数的控制,同时也没有进行拖拽范围的控制。
效果实现
我们首先来大致看看怎么做分解:
- 一个圆环
- 一个渐变色
- 一个控制球
- 一个显示文字
首先看看圆环怎么实现的,很简单,我们利用Core Graphic使用如下代码即可以画出一个圆圈,只要加上描边宽度,就可以形成圆环效果。
CGContextAddArc(
ctx,
self.frame.size.width/2,
self.frame.size.height/2,
self.radius,
0,
2.0 * M_PI,
0
)
UIColor(red: 0, green: 0, blue: 0, alpha: 1.0).set()
CGContextSetLineWidth(ctx, 72)
CGContextSetLineCap(ctx, kCGLineCapButt)
CGContextDrawPath(ctx, kCGPathStroke)
然后我们的圆环背景色是渐变的,这可怎么办?我们直接使用CAGradientLayer吗?当然那是其中之一的方法,不过这次我们试试用Mask + 背景色的方式实现。什么是Mask呢?简单来理解就是,如果你想做出非常复杂的形状,你可以将构造一个包含这种形状的图片,需要显示形状的地方用非白色的颜色来填充,不显示的地方用白色填充。因此,我们构建一个从上到下的渐变色背景,然后配合黑色的圆环进行Mask,就可以得到带有渐变色背景的。
CGContextSaveGState(ctx)
CGContextClipToMask(ctx, self.bounds, mask)
let startColorComponents = CGColorGetComponents(startColor.CGColor)
let endColorComponents = CGColorGetComponents(endColor.CGColor)
let components = [
startColorComponents[0], startColorComponents[1], startColorComponents[2], 1.0,
endColorComponents[0], endColorComponents[1], endColorComponents[2], 1.0
]
let gradient = CGGradientCreateWithColorComponents(CGColorSpaceCreateDeviceRGB(), components, nil, 2)
CGContextDrawLinearGradient(
ctx,
gradient,
CGPointMake(CGRectGetMidX(rect), CGRectGetMinY(rect)),
CGPointMake(CGRectGetMidX(rect), CGRectGetMaxY(rect)),
0
);
CGContextRestoreGState(ctx);
到此,绘画的工作基本就结束了,画白色小球的原理很简单,也不赘述了。我们下面来说一下根据手势来控制白色小球旋转位置,主要的思路还是控制位置来计算弧度。
override func touchesMoved(touches: Set<NSObject>, withEvent event: UIEvent) {
//println("Touches Moved")
if let touch = touches.first as? UITouch {
var location = touch.locationInView(self)
moveHandle(location)
}
}
func computeAngle(p1:CGPoint , p2:CGPoint) -> Double {
var delta = CGPoint(x: p2.x - p1.x, y: p1.y - p2.y)
let radians = Double(atan2(delta.y, delta.x))
let result = toDegree(radians)
return result >= 0 ? result : result + 360
}
其中,有一点我们要特别注意
var delta = CGPoint(x: p2.x - p1.x, y: p1.y - p2.y),在Y轴的计算上,我们需要进行上下翻转的计算,原因就在于我们通过UITouch拿到的location的Y坐标,是UIKit系的坐标体系,Y轴原点在上方,而我们通过绘图的时候需要进行进行Y轴的上下颠倒。
此外,根据计算的弧度,来更新小球的位置,由于我们是逆时针的slider,所以我们需要用 360 减去我们实际计算得到的弧度。
一些感受
真的,Swift中的类型安全太恶心了,不能忍,于是只好玩起了操作符重载
func -(lhs:CGFloat, rhs:Double) -> CGFloat {
return lhs - CGFloat(rhs)
}
func +(lhs:Double, rhs:CGFloat) -> CGFloat {
return CGFloat(lhs) + rhs
}
func +(lhs:CGFloat, rhs:Double) -> CGFloat {
return lhs + CGFloat(rhs)
}
func *(lhs:Double, rhs:CGFloat) -> CGFloat {
return CGFloat(lhs) * rhs
}
func *(lhs:CGFloat, rhs:Double) -> CGFloat {
return lhs * CGFloat(rhs)
}
func /(lhs:Double, rhs:CGFloat) -> CGFloat {
return CGFloat(lhs) / rhs
}
func /(lhs:CGFloat, rhs:Double) -> CGFloat {
return lhs / CGFloat(rhs)
}
最后附上项目地址
好了,不多说了,我要升级El Captain了。