说出以下情况:
我画了一个四边形的形状,这是UIView的面具。我将形状图层表示为maskLayer
。 maskLayer
以不对称的方式裁剪UIView的底部。
然后我想在动画中完全展示我的UIView。动画应该在maskLayer的左侧下降到UIView的底部,然后.2秒后我的maskLayer的右侧也下降到UIView的底部,从而完全揭示了UIView的实体。
我的方法是首先按下左边的行,然后按下面的代码右下角:
//this quadrilateral will put down left corner to the bottom of screen
var path2 = UIBezierPath()
path2.moveToPoint(CGPointZero)
path2.addLineToPoint(CGPoint(x: 0, y: frame.height))
path2.addLineToPoint(CGPoint(x: frame.width, y: frame.height / goldRatio / goldRatio))
path2.addLineToPoint(CGPoint(x: frame.width, y: 0))
path2.closePath()
//this rectangle path will put down both corner to the bottom of screen
//thus fix the view to its original shape
var path3 = UIBezierPath()
path3.moveToPoint(CGPointZero)
path3.addLineToPoint(CGPoint(x: 0, y: frame.height))
path3.addLineToPoint(CGPoint(x: frame.width, y: frame.height))
path3.addLineToPoint(CGPoint(x: frame.width, y: 0))
path3.closePath()
我花了2个小时试图弄明白无济于事。请你给我一些关于如何实现这一目标的说明。
初始状态如下:
结束状态如下:
我真的很感谢你的帮助!
答案 0 :(得分:0)
最容易做到这一点的方法......作弊。
不要试图为它真正不需要它的形状的路径设置动画。
你应该做的就是这样。
创建最终的状态视图。屏幕底部的矩形,上面有UI等等......
此最终状态视图不会移动。它永远都在这里。
现在创建另一个视图并将其作为最终状态视图下方的子视图插入。在此,您可以添加一个角形切角的形状图层。
现在你需要做的就是向下动画这个角度视图的位置,直到它完全低于最终的状态视图。
如果颜色相同,则会产生动画形状路径的效果。
要获得不同的速度,您可以将矩形形状图层旋转到45度。然后在视图向下滑动时将其设置为0度?
事实上,您可以使用旋转和移动的单个形状图层来完成此操作。
答案 1 :(得分:0)
要执行此类动画,您通常会使用CADisplayLink
(有点像计时器,但链接到显示的更新而不是某个任意间隔)来重复更改path
关联具有所需的形状。我认为如果您使用CAShapeLayer
并且只更改此形状的path
属性,这是最简单的。
为了使这项工作,您需要一个函数来表示给定时间点的路径(或者更容易,一个路径在动画持续时间内某个percentageComplete
的瞬间)。由于你有一个规则的形状(通常具有相同的点数),你可以简单地在startPoints
和endPoints
的某个数组之间进行插值。
因此,创建形状图层,捕获开始时间,启动显示链接,然后对于显示链接的每个“勾号”,计算总animationDuration
的百分比,并更新形状层的路径相应:
class ViewController: UIViewController {
let animationDuration = 2.0
var displayLink: CADisplayLink!
var startTime: CFAbsoluteTime!
var shapeLayer: CAShapeLayer!
let goldRatio: CGFloat = 1.6180339887
var startPoints:[CGPoint]!
var endPoints:[CGPoint]!
override func viewDidLoad() {
super.viewDidLoad()
self.startAnimation()
}
func startAnimation() {
startPoints = [
CGPoint(x: 0, y: view.bounds.size.height),
CGPoint(x: 0, y: view.bounds.size.height - view.bounds.size.height / goldRatio),
CGPoint(x: view.bounds.size.width, y: 0),
CGPoint(x: view.bounds.size.width, y: view.bounds.size.height)
]
endPoints = [
CGPoint(x: 0, y: view.bounds.size.height),
CGPoint(x: 0, y: view.bounds.size.height * 0.75),
CGPoint(x: view.bounds.size.width, y: view.bounds.size.height * 0.75),
CGPoint(x: view.bounds.size.width, y: view.bounds.size.height)
]
assert(startPoints.count == endPoints.count, "Point counts don't match")
createShape()
startDisplayLink()
}
func startDisplayLink() {
displayLink = CADisplayLink(target: self, selector: "handleDisplayLink:")
startTime = CFAbsoluteTimeGetCurrent()
displayLink.addToRunLoop(NSRunLoop.mainRunLoop(), forMode: NSRunLoopCommonModes)
}
func stopDisplayLink() {
displayLink.invalidate()
displayLink = nil
}
func handleDisplayLink(displayLink: CADisplayLink) {
var percent = CGFloat((CFAbsoluteTimeGetCurrent() - startTime) / animationDuration)
if percent >= 1.0 {
percent = 1.0
stopDisplayLink()
}
updatePathBasedUponPercentComplete(percent)
}
func createShape() {
shapeLayer = CAShapeLayer()
shapeLayer.fillColor = UIColor.blueColor().CGColor
shapeLayer.strokeColor = UIColor.clearColor().CGColor
updatePathBasedUponPercentComplete(0.0)
view.layer.addSublayer(shapeLayer)
}
func updatePathBasedUponPercentComplete(percentComplete: CGFloat) {
shapeLayer.path = pathBasedUponPercentComplete(percentComplete, frame: view.frame).CGPath
}
func pathBasedUponPercentComplete(percentComplete: CGFloat, frame: CGRect) -> UIBezierPath {
var path = UIBezierPath()
for i in 0 ..< startPoints.count {
let point = CGPoint(
x: startPoints[i].x + (endPoints[i].x - startPoints[i].x) * percentComplete,
y: startPoints[i].y + (endPoints[i].y - startPoints[i].y) * percentComplete
)
if i == 0 {
path.moveToPoint(point)
} else {
path.addLineToPoint(point)
}
}
path.closePath()
return path
}
}