什么是创建循环动画的正确方法吗? [英] What is the right way of creating circle animation?
问题描述
我刚刚看到这个形象,也同样吸引了我,如何在斯威夫特创造这种类型的动画:
I just saw this image and it's interesting to me, how to create such type of animation in Swift:
所以,我在圈内很多灰色的牙齿,当我设置的角度,例如45度,将0..45度以内填补这些灰色的牙齿变成蓝色。
So, I have many gray teeth in circle and when I set the angle, for example 45degree it will fill these gray teeth into blue within 0..45 degree.
您可以只解释我做的正确的方式,也可以显示不同的片段(这将是伟大的)。后来我将搜索或阅读它。
You can just explain me the right way of doing it or you can show different snippets(it would be great). And later I will search or read about it.
在此先感谢!
推荐答案
如果您只需要单个的牙齿来改变,而不是用牙齿掩码实心填充颜色,你可以使用核芯显卡,而不是核心动画(虽然核心动画一般是preferred)。因此,为了做到这一点,我们应该做以下几点:
If you only need the individual 'teeth' to change color, instead of using the teeth as masks for a solid fill, you can use Core Graphics instead of Core Animation (although Core Animation is generally preferred). So in order to do this, we should be doing the following:
- 子类
的UIView
来插入我们的绘图code - 创建路径对象的数组,包裹在
UIBezierPath
- 设置更新进度值定时器和
setNeedsDisplay
- 在
的drawRect:
,绘制的路径和填充每个取决于进度 分配
- Subclass
UIView
to insert our drawing code - Create an array of path objects, wrapped in
UIBezierPath
- Setup a timer to update a progress value and
setNeedsDisplay
- In
drawRect:
, draw the paths and assign a fill to each depending on the progress
首先,让我们定义打算在该的UIView
子类是工作中的变量。
First of all, lets define the variables we're going to be working with in this UIView
subclass.
class TeethLoaderView : UIView {
let numberOfTeeth = UInt(60) // Number of teeth to render
let teethSize = CGSize(width:8, height:45) // The size of each individual tooth
let animationDuration = NSTimeInterval(5.0) // The duration of the animation
let highlightColor = UIColor(red: 29.0/255.0, green: 175.0/255.0, blue: 255.0/255.0, alpha: 1) // The color of a tooth when it's 'highlighted'
let inactiveColor = UIColor(red: 233.0/255.0, green: 235.0/255.0, blue: 236.0/255.0, alpha: 1) // The color of a tooth when it isn't 'hightlighted'
var progress = NSTimeInterval(0.0) // The progress of the loader
var paths = [UIBezierPath]() // The array containing the UIBezier paths
var displayLink = CADisplayLink() // The display link to update the progress
var teethHighlighted = UInt(0) // Number of teeth highlighted
...
现在让我们添加一个函数来创建我们的路。
Now let's add a function to create our paths.
func getPaths(size:CGSize, teethCount:UInt, teethSize:CGSize, radius:CGFloat) -> [UIBezierPath] {
let halfHeight = size.height*0.5;
let halfWidth = size.width*0.5;
let deltaAngle = CGFloat(2*M_PI)/CGFloat(teethCount); // The change in angle between paths
// Create the template path of a single shape.
let p = CGPathCreateWithRect(CGRectMake(-teethSize.width*0.5, radius, teethSize.width, teethSize.height), nil);
var pathArray = [UIBezierPath]()
for i in 0..<teethCount { // Copy, translate and rotate shapes around
let translate = CGAffineTransformMakeTranslation(halfWidth, halfHeight);
var rotate = CGAffineTransformRotate(translate, deltaAngle*CGFloat(i))
let pathCopy = CGPathCreateCopyByTransformingPath(p, &rotate)!
pathArray.append(UIBezierPath(CGPath: pathCopy)) // Populate the array
}
return pathArray
}
这是相当简单的。我们只需要创建一个路径为一个单一的'牙齿',然后复制,因为我们有多少牙齿需要,翻译和为每一个旋转的路径这个路径。
This is fairly simple. We just create a path for a single 'tooth' and then copy this path for how many teeth we need, translating and rotating the path for each one.
接下来我们要建立我们的观点。我要去一个 CADisplayLink
的定时器,使得动画在执行上的所有设备相同的速度。
Next we want to setup our view. I'm going to a CADisplayLink
for the timer so that the animation performs at the same speed on all devices.
override init(frame: CGRect) {
super.init(frame: frame)
commonSetup()
}
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
commonSetup()
}
private func commonSetup() {
self.backgroundColor = UIColor.whiteColor()
paths = getPaths(frame.size, teethCount: numberOfTeeth, teethSize: teethSize, radius: ((frame.width*0.5)-teethSize.height))
displayLink = CADisplayLink(target: self, selector: #selector(displayLinkDidFire));
displayLink.addToRunLoop(NSRunLoop.mainRunLoop(), forMode: NSRunLoopCommonModes)
}
下面我们就设置背景颜色,以及设置计时器我们并初始化我们将要使用的路径。接下来我们要建立一个函数来改变视图的进展情况时, CADisplayLink
火灾。
Here we just set the background color, as well as setup our timer and initialise the paths we're going to be using. Next we want to setup a function to change the progress of the view when the CADisplayLink
fires.
func displayLinkDidFire() {
progress += displayLink.duration/animationDuration
if (progress > 1) {
progress -= 1
}
let t = teethHighlighted
teethHighlighted = UInt(round(progress*NSTimeInterval(numberOfTeeth))) // Calculate the number of teeth to highlight
if (t != teethHighlighted) { // Only call setNeedsDisplay if the teethHighlighted changed
setNeedsDisplay()
}
}
这里没有什么复杂的,我们只是更新进度和 teethHighlighted
和呼叫 setNeedsDisplay()
重绘的观点,如果 teethHighlighted
改变。
Nothing complicated here, we just update the progress and teethHighlighted
and call setNeedsDisplay()
to redraw the view, if teethHighlighted
changed.
最后,我们要画的看法。
Finally, we want to draw the view.
override func drawRect(rect: CGRect) {
let ctx = UIGraphicsGetCurrentContext()
CGContextScaleCTM(ctx, -1, -1) // Flip the context to the correct orientation
CGContextTranslateCTM(ctx, -rect.size.width, -rect.size.height)
for (index, path) in paths.enumerate() { // Draw each 'tooth'
CGContextAddPath(ctx, path.CGPath);
let fillColor = (UInt(index) <= teethHighlighted) ? highlightColor:inactiveColor;
CGContextSetFillColorWithColor(ctx, fillColor.CGColor)
CGContextFillPath(ctx)
}
}
如果你想往下走的Core Animation路径,我适应这个code到核心动画层
If you wanted to go down the Core Animation path, I adapted this code into a Core Animation layer
完整的项目: https://github.com/originaluser2/Circle-Loader
Full project: https://github.com/originaluser2/Circle-Loader
这篇关于什么是创建循环动画的正确方法吗?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!