本文是系列文章的第二篇。
看过上一篇文章的同学,已经知道标题中的“景”指代 view,“窗”指代 view.mask,窗景篇就是在梳理 mask 及 mask 动画。如果你还不熟悉 iOS 的 mask,建议先看一下第一篇。
相对于景来说,窗的变化更多样一些,所以本文我们重点来看一下窗的效果。
我们从3个维度来看:窗在动吗?窗在变吗?有几个窗?
很多动画就是这3个维度的单独体现,或者组合后的效果。我们先看一下各个维度的单独效果,然后再来看一下它们的组合效果。
一、窗动
前文中,我们用一个圆作为窗,先贴张图回忆一下:
我们大都做过基本的动画,因此可以想到,只要动画地改变圆 mask 的中心位置,就可以让窗动起来。
效果如下面的动图所示:
示意代码如下:
/// viewDidLoad
// 景
frontView.frame = UIScreen.main.bounds
view.addSubview(frontView)
// 圆窗
let mask = CircleView()
mask.frame = CGRect(x: 0, y: 0, width: 200, height: 200)
mask.center = CGPoint(x: 100, y: 100)
self.mask = mask
frontView.mask = mask
// 窗动
startAnimation()
/// startAnimation
// 动画地改变 mask 的中心
private func startAnimation() {
mask.layer.removeAllAnimations()
let anim = CAKeyframeAnimation(keyPath: "position")
let bound = UIScreen.main.bounds
anim.values = [CGPoint(x: 100, y: 250), CGPoint(x:bound.width - 100 , y: 250), CGPoint(x: bound.midX, y: 450), CGPoint(x: 100, y: 250)]
anim.duration = 4
anim.repeatCount = Float.infinity
mask.layer.add(anim, forKey: nil)
}
让窗动起来非常简单,这简单的效果也可以成为其他效果的基础。
比如我们加入一个 pan(拖动) 手势,实现这样一个效果:
思路很简单:
- 初始时一片黑色,窗的大小为0
- pan 手势开始时,开始显示窗户
- pan 手势拖动时,移动窗
- pan 手势结束时,窗的大小恢复为0,回归一片黑色
示意代码如下:
// 在刚才窗动的代码基础上
// 添加 pan 手势来控制 mask 的 center
@objc func onPan(_ pan: UIPanGestureRecognizer) {
switch pan.state {
case .began:
// 拖动开始,显示窗
mask.frame = CGRect(x: 0, y: 0, width: 200, height: 200)
mask.center = pan.location(in: pan.view)
case .changed:
// 拖动过程,移动窗
mask.center = pan.location(in<