Beginning iOS Animation Series

#Beginning iOS Animation Series
对应raywenderlich上Beginning iOS Animation Series (Swift 2)的内容。

##Constraint Animations
Constraint的一般形式为:
这里写图片描述

其中multiplier为只读

Constraint Animations的简单使用方式为:
这里写图片描述

这里修改的是constant

例如:

  @IBAction func actionToggleMenu(sender: AnyObject) {
    isMenuOpen = !isMenuOpen
    
    menuHeightConstrait.constant = isMenuOpen ? 200.0 : 60.0;
    closeButtonTrailing.constant = isMenuOpen ? 16.0 : 8.0;
    titleLabel.text = isMenuOpen ? "Select Item" : "Packing List";
    
    UIView.animateWithDuration(0.33, delay: 0, options: [.CurveEaseOut], animations: {
        let angle = self.isMenuOpen ? CGFloat(M_PI_4) : 0
        self.buttonMenu.transform = CGAffineTransformMakeRotation(angle);
        self.slider.alpha = self.isMenuOpen ? 1 : 0;
        self.view.layoutIfNeeded()
        }, completion: nil)
    
  }

如何修改mutiplier?
找到对应的constraint,创建一个新的constraint来替换。

for constraint in titleLabel.superview!.constraints {
    if constraint.identifier == "TitleCenterX" {
        constraint.constant = isMenuOpen ? -100.0 : 0.0
    }
    if constraint.identifier == "TitleCenterY" {
        constraint.active = false
        let newConstraint = NSLayoutConstraint(
            item: titleLabel,
            attribute: .CenterY,
            relatedBy: .Equal,
            toItem: titleLabel.superview!,
            attribute: .CenterY,
            multiplier: isMenuOpen ? 0.67 : 1.0,
            constant: 5.0);
        newConstraint.identifier = "TitleCenterY"
        newConstraint.active = true
    }
}

下面是其对应的Challenge中的动画内容,主要也是修改constant,但是其创建constraint的方式很特别,如下:

let conX = imageView.centerXAnchor.constraintEqualToAnchor(view.centerXAnchor)
let conBottom = imageView.bottomAnchor.constraintEqualToAnchor(view.bottomAnchor, constant: imageView.frame.height)
let conWidth = imageView.widthAnchor.constraintEqualToAnchor(view.widthAnchor, multiplier: 0.33, constant: -50.0)
let conHeight = imageView.heightAnchor.constraintEqualToAnchor( imageView.widthAnchor)
NSLayoutConstraint.activateConstraints([conX, conBottom, conWidth, conHeight])
view.layoutIfNeeded()

conBottom.constant = -imageView.frame.size.height/2
conWidth.constant = 0.0


UIView.animateWithDuration(0.33, delay: 0.0, options: [.CurveEaseOut], animations: { 
    self.view.layoutIfNeeded()
    }, completion: nil);


UIView.animateKeyframesWithDuration(0.67, delay: 2.0, options: [], animations: { 
    conBottom.constant = imageView.frame.height
    conWidth.constant = -50.0
    self.view.layoutIfNeeded()
    }) { _ in
        imageView.removeFromSuperview()
}

动画效果:
动画效果

##Spring Animations

UIView.animateWithDuration(1.0, delay: 0,
  
  usingSpringWithDamping: 0.4, initialSpringVelocity: 10.0,
  
  options: [.CurveEaseOut], animations: {
  
  self.view.layoutIfNeeded()
  
  let angle = self.isMenuOpen ? CGFloat(M_PI_4) : 0
  self.buttonMenu.transform = CGAffineTransformMakeRotation(angle)
  
  }, completion: nil)

Spring damping: the smaller the damping the more the view bounces at the end of the animation. The closer the parameter is to 1.0 the less bouncing you get at the end of the animation; if you try 1.0 you get straight movement from point A to B)

Initial velocity: If you set this parameter to 1.0 and the animation moves the view 50 points across the screen - it will give the view 50 points/sec of initial velocity. If you set the parameter to 2.0 - the view will have 100 points/sec initial velocity.

具体的解释可以参考使用 iOS 8 Spring Animation API 创建动画

usingSpringWithDamping的范围为0.0f1.0f,数值越小「弹簧」的振动效果越明显
initialSpringVelocity则表示初始的速度,数值越大一开始移动越快。

##View Transitions
Three things that can trigger a transition:

  • hidden
  • addSubview()
  • removeFromParent()

hidden

delay(seconds: 1.0, completion: {

    UIView.transitionWithView(imageView, duration: 1.0,
        options: [UIViewAnimationOptions.TransitionFlipFromBottom],
        animations: {
            imageView.hidden = true
        }, completion: { _ in
            
        })
    
    })

动画效果:

动画效果

removeFromParent()

    delay(seconds: 0.35, completion: {
        self.actionToggleMenu(self)
    })
    
    let titleBar = slider.superview!
    UIView.transitionWithView(titleBar, duration: 0.5, options: [.CurveEaseOut, .TransitionFlipFromBottom], animations: {
        self.slider.removeFromSuperview()
        }, completion: {_ in
            titleBar.addSubview(self.slider)
    })
    
  }

动画效果

动画效果

Keyframe Animations

主要使用方法是

    @available(iOS 7.0, *)
    open class func animateKeyframes(withDuration duration: TimeInterval, delay: TimeInterval, options: UIView.KeyframeAnimationOptions = [], animations: @escaping () -> Void) async -> Bool

然后在其中嵌套使用addKeyframeWithRelativeStartTime(_: relativeDuration: animations: )

    @available(iOS 7.0, *)
    open class func addKeyframe(withRelativeStartTime frameStartTime: Double, relativeDuration frameDuration: Double, animations: @escaping () -> Void)

该方法有三个参数:

  • frameStartTime:关键帧开始时间,该时间是相对整个关键帧动画持续时间的相对时间,一般值在0到1之间。如果为0,则表明这一关键帧从整个动画的第0秒开始执行,如果设为0.5,则表明从整个动画的中间开始执行。
  • relativeDuration:关键帧持续时间,该时间同样是相对整个关键帧动画持续时间的相对时间,一般值也在0到1之间。如果设为0.25,则表明这一关键帧的持续时间为整个动画持续时间的四分之一。
  • animations:设置视图动画属性的动画闭包。

如例子:

  func planeDepart() {
    let originalCenter = planeImage.center

    UIView.animateKeyframes(withDuration: 1.5, delay: 0.0, animations: {
      //add keyframes
      UIView.addKeyframe(
        withRelativeStartTime: 0.0,
        relativeDuration: 0.25
      ) {
        self.planeImage.center.x += 80.0
        self.planeImage.center.y -= 10.0
      }
	.......
    }, completion: nil)
  }

开始时间为0.0,表示直接开始
动画总时长为1.5s,所以第一个关键帧动画大概会持续1.5 * 0.25 = 0.375
示意图01

      UIView.addKeyframe(withRelativeStartTime: 0.1, relativeDuration: 0.4) {
        self.planeImage.transform = CGAffineTransform(rotationAngle: -.pi / 8)
      }

0.1表示关键帧从动画的 10% 处开始,持续 40%总持续时间
示意图02

代码为:

    UIView.animateKeyframesWithDuration(1.5, delay: 0.0,
      options: [], animations: {
      
        UIView.addKeyframeWithRelativeStartTime(0.0, relativeDuration: 0.25, animations: {
          self.planeImage.center.x += 80.0
          self.planeImage.center.y -= 10.0
        })
        
        UIView.addKeyframeWithRelativeStartTime(0.1, relativeDuration: 0.4, animations: {
          self.planeImage.transform = CGAffineTransformMakeRotation(CGFloat(-M_PI_4/2))
        })
        
        UIView.addKeyframeWithRelativeStartTime(0.25, relativeDuration: 0.25, animations: {
          self.planeImage.center.x += 100.0
          self.planeImage.center.y -= 50.0
          self.planeImage.alpha = 0
        })
        
        UIView.addKeyframeWithRelativeStartTime(0.51, relativeDuration: 0.01, animations: {
          self.planeImage.transform = CGAffineTransformIdentity
          self.planeImage.center = CGPoint(x: 0, y: originalCenter.y)
        })
        
        UIView.addKeyframeWithRelativeStartTime(0.55, relativeDuration: 0.45, animations: {
          self.planeImage.alpha = 1.0
          self.planeImage.center = originalCenter
        })
        
      }, completion: nil)

动画效果为:
动画效果

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值