CAShapeLayer 路径动画在完成动画之前收缩
CAShapeLayer path animation shrinking before completing animation
我正在尝试为图层的 CGpath 的旋转设置动画。
旋转效果很好,但由于某种原因,路径似乎缩小了,然后又变大了。我只是想让它显示一个旋转动画。我不想让它缩小
这是一个视频。
这是代码
class ViewController: UIViewController {
@IBOutlet weak var overlayView: UIView!
override func viewDidLoad() {
super.viewDidLoad()
let maskLayer = CAShapeLayer()
let path = UIBezierPath(rect: view.bounds)
let mask = UIBezierPath.drawSquare(width: 100, center: view.center)
// Makes it so we can see through the center of the view
maskLayer.fillRule = CAShapeLayerFillRule.evenOdd
path.append(mask)
maskLayer.path = path.cgPath
overlayView.layer.mask = maskLayer
}
@IBAction func rotateView(_ sender: Any) {
let maskPath = UIBezierPath.drawSquare(width: 100, center: overlayView.center)
let path = UIBezierPath(rect: overlayView.frame)
let bounds: CGRect = maskPath.cgPath.boundingBox
let center = CGPoint(x: bounds.midX, y: bounds.midY)
let radians = 90 / 180.0 * .pi
var transform: CGAffineTransform = .identity
transform = transform.translatedBy(x: center.x, y: center.y)
transform = transform.rotated(by: radians)
transform = transform.translatedBy(x: -center.x, y: -center.y)
maskPath.apply(transform)
path.append(maskPath)
// create new animation
let anim = CABasicAnimation(keyPath: "path")
anim.toValue = path.cgPath
(overlayView.layer.mask as? CAShapeLayer)?.add(anim, forKey: "path")
}
}
extension UIBezierPath{
static func drawSquare(width: CGFloat, center: CGPoint) -> UIBezierPath {
let rect = CGRect(x: center.x - width/2, y: center.y - width/2, width: width, height: width)
let path = UIBezierPath()
path.move(to: rect.origin)
path.addLine(to: CGPoint(x: rect.maxX, y: rect.minY))
path.addLine(to: CGPoint(x: rect.maxX, y: rect.maxY))
path.addLine(to: CGPoint(x: rect.minX, y: rect.maxY))
path.close()
return path
}
}
您的“剪切框”正在缩小和扩大,因为您正在使用 路径 动画。
当您为从一组点到另一组点的路径设置动画时,每个点将从其起点到终点采用一条直线。
几种可视化方法...
首先,我们将向镂空遮罩框添加一个“轮廓”框:
如您所见,每个角都直接通往下一个位置。
如果我们突出一侧,它可能更明显一点:
而且,为了更清楚,我们可以对角进行编号:
所以,如果我们想在不改变大小的情况下旋转正方形,我们可以使用关键帧动画和运行沿圆的角:
或者,更简单的方法是旋转遮罩 层 而不是其路径:
let radians = 90 / 180.0 * .pi
let anim = CABasicAnimation(keyPath: "transform.rotation.z")
anim.toValue = radians
anim.duration = 1.0
(overlayView.layer.mask as? CAShapeLayer)?.add(anim, forKey: "layerRotate")
毫无疑问,我们注意到遮罩层框架没有完全覆盖 overlayView 框架。
所以,我们可以通过增大遮罩层框架来解决这个问题。
我们可以准确地计算它需要多大,但是因为形状图层非常有效,我们只将它设为正方形,比长轴大 1.5 倍:
所以当它旋转时,它会覆盖视图:
我们就此结束:
我正在尝试为图层的 CGpath 的旋转设置动画。
旋转效果很好,但由于某种原因,路径似乎缩小了,然后又变大了。我只是想让它显示一个旋转动画。我不想让它缩小
这是一个视频。
这是代码
class ViewController: UIViewController {
@IBOutlet weak var overlayView: UIView!
override func viewDidLoad() {
super.viewDidLoad()
let maskLayer = CAShapeLayer()
let path = UIBezierPath(rect: view.bounds)
let mask = UIBezierPath.drawSquare(width: 100, center: view.center)
// Makes it so we can see through the center of the view
maskLayer.fillRule = CAShapeLayerFillRule.evenOdd
path.append(mask)
maskLayer.path = path.cgPath
overlayView.layer.mask = maskLayer
}
@IBAction func rotateView(_ sender: Any) {
let maskPath = UIBezierPath.drawSquare(width: 100, center: overlayView.center)
let path = UIBezierPath(rect: overlayView.frame)
let bounds: CGRect = maskPath.cgPath.boundingBox
let center = CGPoint(x: bounds.midX, y: bounds.midY)
let radians = 90 / 180.0 * .pi
var transform: CGAffineTransform = .identity
transform = transform.translatedBy(x: center.x, y: center.y)
transform = transform.rotated(by: radians)
transform = transform.translatedBy(x: -center.x, y: -center.y)
maskPath.apply(transform)
path.append(maskPath)
// create new animation
let anim = CABasicAnimation(keyPath: "path")
anim.toValue = path.cgPath
(overlayView.layer.mask as? CAShapeLayer)?.add(anim, forKey: "path")
}
}
extension UIBezierPath{
static func drawSquare(width: CGFloat, center: CGPoint) -> UIBezierPath {
let rect = CGRect(x: center.x - width/2, y: center.y - width/2, width: width, height: width)
let path = UIBezierPath()
path.move(to: rect.origin)
path.addLine(to: CGPoint(x: rect.maxX, y: rect.minY))
path.addLine(to: CGPoint(x: rect.maxX, y: rect.maxY))
path.addLine(to: CGPoint(x: rect.minX, y: rect.maxY))
path.close()
return path
}
}
您的“剪切框”正在缩小和扩大,因为您正在使用 路径 动画。
当您为从一组点到另一组点的路径设置动画时,每个点将从其起点到终点采用一条直线。
几种可视化方法...
首先,我们将向镂空遮罩框添加一个“轮廓”框:
如您所见,每个角都直接通往下一个位置。
如果我们突出一侧,它可能更明显一点:
而且,为了更清楚,我们可以对角进行编号:
所以,如果我们想在不改变大小的情况下旋转正方形,我们可以使用关键帧动画和运行沿圆的角:
或者,更简单的方法是旋转遮罩 层 而不是其路径:
let radians = 90 / 180.0 * .pi
let anim = CABasicAnimation(keyPath: "transform.rotation.z")
anim.toValue = radians
anim.duration = 1.0
(overlayView.layer.mask as? CAShapeLayer)?.add(anim, forKey: "layerRotate")
毫无疑问,我们注意到遮罩层框架没有完全覆盖 overlayView 框架。
所以,我们可以通过增大遮罩层框架来解决这个问题。
我们可以准确地计算它需要多大,但是因为形状图层非常有效,我们只将它设为正方形,比长轴大 1.5 倍:
所以当它旋转时,它会覆盖视图:
我们就此结束: