美文网首页动画
第 17 章:圆环菜单的动画效果

第 17 章:圆环菜单的动画效果

作者: sing_crystal | 来源:发表于2016-05-15 21:34 被阅读73次

    原文链接
    作者:C4 开源项目
    译者:Crystal Sun
    全部章节请关注此文集C4教程翻译
    校对后的内容请看这里

    尽管我已经把这章从上一章节里分出来了,我们还是要在 MenuRings.swift 文件里进行开发。运行应用,确保你看到的应用效果如下图:

    如果不是这个效果,回到前一章节里,确保所有的变量设置正确,特别是菜单里的每条线、每个内环的变量值。

    厚指环的动画效果

    对每个组件我们都会设置自己的进出效果和转换效果。对于厚指环的动画效果来说,我们先在类里添加下面两个变量:

    var thickRingOut : ViewAnimation?
    var thickRingIn : ViewAnimation?
    

    现在,创建一个方法,写代码:

    func createThickRingAnimations() {
        thickRingOut = ViewAnimation(duration: 0.5) {
            self.thickRing?.frame = self.thickRingFrames[1]
        }
        thickRingOut?.curve = .EaseOut
        
        thickRingIn = ViewAnimation(duration: 0.5) {
            self.thickRing?.frame = self.thickRingFrames[0]
        }
        thickRingIn?.curve = .EaseOut
    }
    

    这个方法设置了两个动画,第一个 out 设置的是厚指环的新 frame,告诉 shape 更新自己的路径,强迫 shape 重画路径直到符合 frame。第二个则与 out 相反。

    让我们测试一下。

    创建下面这两个方法:

    func animOut() {
        delay(1.0) {
            self.thickRingOut?.animate()
        }
        delay(2.0) {
            self.animIn()
        }
    }
    
    func animIn() {
        delay(1.0) {
            self.thickRingIn?.animate()
        }
        delay(2.0) {
            self.animOut()
        }
    }
    

    接着在 setup 里输入下列代码:

    self.createThickRingAnimations()
    animOut()
    

    得到了这样的效果:

    薄指环的动画效果(出)

    先给我们的薄指环创建动画效果,和之前的步骤有些不同,因为我们需要协调五条线,之前只是一条线,所以我们使用循环体来创建,存储到数组中。

    在类里增加下面两个变量:

    var thinRingsOut : ViewAnimationSequence?
    

    接着,增加下列方法:

    func createThinRingsOutAnimations() {
        var animationArray = [ViewAnimation]()
        for i in 0..<self.thinRings.count-1 {
            let anim = ViewAnimation(duration: 0.075 + Double(i) * 0.01) {
                let circle = self.thinRings[i]
                //每个动画都大于第一个
                if (i > 0) {
                    //把指环的透明度调整到 1.0
                    ViewAnimation(duration: 0.0375) {
                        circle.opacity = 1.0
                        }.animate()
                }
                
                circle.frame = self.thinRingFrames[i+1]
            }
            anim.curve = .EaseOut
            animationArray.append(anim)
        }
        thinRingsOut = ViewAnimationSequence(animations: animationArray)
    }
    

    这个创建了一系列动画变量,基在很多章节之前设置的目标 frame 的值来填充动画。

    这个方法创建了一个动画数组,然后运行循环:

    1. 抓住每个瘦指环,从小到大
    2. 创建动画,持续时间基于当前的 index(0.075 + Double(i) + 0.01)
    3. 检查每一行的 index 是否大于零,比如,不是内圆
    4. 对于任何一个非内圆,创建一个不透明的动画,执行后会立即消失
    5. 抓住当前目标的 frame,也就是当前 index + 1
    6. 设置当前圆环的 frame,调用 updatePath
    7. 设置动画的曲线为 .EaseOut
    8. 把动画添加到数组里

    循环结束后,创建完成 thinRingsOut 序列。

    薄指环动画效果(入)

    回来的动画和出的动画非常相似,仅仅有几处地方不同。

    在类里增加下列变量:

    var thinRingsIn : ViewAnimationSequence?
    

    增加下列方法:

    func createThinRingsInAnimations() {
        var animationArray = [ViewAnimation]()
        for i in 1...self.thinRings.count {
            let anim = ViewAnimation(duration: 0.075 + Double(i) * 0.01, animations: { () -> Void in
                let circle = self.thinRings[self.thinRings.count - i]
                if self.thinRings.count - i > 0 {
                    ViewAnimation(duration: 0.0375) {
                        circle.opacity = 0.0
                        }.animate()
                }
                circle.frame = self.thinRingFrames[self.thinRings.count - i]
            })
            anim.curve = .EaseOut
            animationArray.append(anim)
        }
        thinRingsIn = ViewAnimationSequence(animations: animationArray)
    }
    

    不同之处在于:

    1. 这里的数学计算表示循环体和出的效果正好相反:self.thinRings.count - 1
    2. 透明度调整为 0.0
    3. 由于我们总是想获取数组“之前”的数字(比如 -1),所以我们的循环执行如下:for i in 1...self.thinRings.count

    虚线环的动画效果

    要完成这些动画,还需要创建两个新的动画变量:

    var revealDashedRings : ViewAnimation?
    var hideDashedRings : ViewAnimation?
    

    增加下列方法:

    func createDashedRingAnimations() {
        revealDashedRings = ViewAnimation(duration: 0.25) {
            self.dashedRings[0].lineWidth = 4
            self.dashedRings[1].lineWidth = 12
        }
        revealDashedRings?.curve = .EaseOut
        
        hideDashedRings = ViewAnimation(duration: 0.25) {
            self.dashedRings[0].lineWidth = 0
            self.dashedRings[1].lineWidth = 0
        }
        hideDashedRings?.curve = .EaseOut
    }
    

    查看一下效果

    想要看出、入效果,需要修改 animOutanimIn 方法,如下:

    func animOut() {
        delay(1.0) {
            self.thickRingOut?.animate()
            self.thinRingsOut?.animate()
            self.revealDashedRings?.animate()
        }
        delay(2.0) {
            self.animIn()
        }
    }
    
    func animIn() {
        delay(1.0) {
            self.thickRingIn?.animate()
            self.thinRingsIn?.animate()
            self.hideDashedRings?.animate()
        }
        delay(2.0) {
            self.animOut()
        }
    }
    

    在 setup() 里调用 animOut():

    createThinRingsOutAnimations()
    createThinRingsInAnimations()
    createDashedRingAnimations()
    

    运行,效果如下图:

    估计现在你已经注意到了,指环和竖线的调速有些问题,不用担心,在最后把所有的组件组合到一起后,会处理这个问题的。

    快要到达终点了。

    分割线

    分割线的动画效果比较简单,除了 Jake 的要求,它们出现的顺序是随机的。翻译一下就是:每次线出现的动画和顺序都是要随机的,要和之前的有所不同。

    我是这样解决这个问题的:

    func revealHideDividingLines(target: Double) {
        var indices = [0,1,2,3,4,5,6,7,8,9,10,11]
        
        for i in 0...11 {
            delay(0.05*Double(i)) {
                let randomIndex = random(below: indices.count)
                let index = indices[randomIndex]
                
                ViewAnimation(duration: 0.1) {
                    self.menuDividingLines[index].strokeEnd = target
                }.animate()
                
                indices.removeAtIndex(randomIndex)
            }
        }
    }
    

    把这些添加到类里。

    这个方法做了下面这些事情:

    1. 获取一个目标(应该是 0.0 或者 1.0
    2. 创建 index 数组
    3. 运行循环,执行 12 次
    4. 每次遍历都从

    接着,测试一下效果:

    func animOut() {
        delay(1.0) {
            self.thickRingOut?.animate()
            self.thinRingsOut?.animate()
        }
    
        delay(1.5) {
            self.revealHideDividingLines(1.0)
        }
    
        delay(2.5) {
            self.animIn()
        }
    
    }
    
    func animIn() {
        delay(0.25) {
            self.revealHideDividingLines(0.0)
        }
    
        delay(1.0) {
            self.thickRingIn?.animate()
            self.thinRingsIn?.animate()
        }
        delay(2.0) {
            self.animOut()
        }
    }
    

    效果如下:

    打扫房子

    现在,不在调用 self.animOUt() 方法,删掉两个动画方法。

    接着创建两个新方法:

    func createRingsLines() {
        createThickRing()
        createThinRings()
        createDashedRings()
        createMenuDividingLines()
    }
    
    func createRingsLinesAnimations() {
        createThickRingAnimations()
        createThinRingsOutAnimations()
        createThinRingsInAnimations()
        createDashedRingAnimations()
    }
    

    更新 setup 方法如下:

    public override func setup() {
      canvas.backgroundColor = clear
      canvas.frame = Rect(0,0,80,80)
      createRingsLines()
      createRingsLinesAnimations()
    }
    

    最后,在类里再添加一个变量:

    var menuIsVisible = false
    

    这最后一个变量我们在之后的章节中会用到。

    MenuRings.swift 源文件。

    本文由 SwiftGG 翻译组翻译,已经获得作者翻译授权。

    相关文章

      网友评论

        本文标题:第 17 章:圆环菜单的动画效果

        本文链接:https://www.haomeiwen.com/subject/lsaprttx.html