CAShapeLayer 遮罩从底部显示

CAShapeLayer mask reveal from bottom

我正在尝试从图像底部创建 "reveal" 效果。 我认为这就像将 anchorPoint 设置为 CGPointMake(0.5, 1.0) 或将 contentsGravity 设置为 kCAGravityTop 一样简单,但是 none 这些选项有效。

我的当前代码有效,但从上到下进行动画处理。这是揭示的想法:http://giphy.com/gifs/xTiTnBzItdgaD1xHMc

我如何使它从下到上进行?

这是代码

    let path                = UIBezierPath(rect: CGRectMake(0, 0, imgEmptyBase.width, imgEmptyBase.height - 80))
    let mask                = CAShapeLayer()
    mask.anchorPoint        = CGPointMake(0.5, 1.0)
    mask.path               = path.CGPath

    imgEmptyBase.layer.mask = mask

    let anim                = CABasicAnimation(keyPath: "path")

    anim.fromValue          = path.CGPath
    anim.toValue            = UIBezierPath(rect: imgEmptyBase.bounds).CGPath
    anim.duration           = 1.0
    anim.fillMode           = kCAFillModeForwards
    anim.removedOnCompletion = false

    imgEmptyBase.layer.mask.addAnimation(anim, forKey: "anim")

我想到了 (2) 个选项。

一种是将动画从值切换到值:

let path                = UIBezierPath(rect: CGRectMake(0, 0, imgEmptyBase.width, imgEmptyBase.height - 80))
let mask                = CAShapeLayer()
mask.anchorPoint        = CGPointMake(0.5, 1.0)
mask.path               = path.CGPath

imgEmptyBase.layer.mask = mask

let anim                = CABasicAnimation(keyPath: "path")

anim.fromValue          = UIBezierPath(rect: imgEmptyBase.bounds).CGPath
anim.toValue            = path.CGPath
anim.duration           = 1.0
anim.fillMode           = kCAFillModeForwards
anim.removedOnCompletion = false

imgEmptyBase.layer.mask.addAnimation(anim, forKey: "anim")

另一种是自行切换贝塞尔曲线路径声明:

let path                = UIBezierPath(rect: imgEmptyBase.bounds).CGPath
let mask                = CAShapeLayer()
mask.anchorPoint        = CGPointMake(0.5, 1.0)
mask.path               = path.CGPath

imgEmptyBase.layer.mask = mask

let anim                = CABasicAnimation(keyPath: "path")

anim.fromValue          = path.CGPath
anim.toValue            = UIBezierPath(rect: CGRectMake(0, 0, imgEmptyBase.width, imgEmptyBase.height - 80))
anim.duration           = 1.0
anim.fillMode           = kCAFillModeForwards
anim.removedOnCompletion = false

imgEmptyBase.layer.mask.addAnimation(anim, forKey: "anim")

检查这个!!

let path = UIBezierPath(rect: CGRectMake(0, denterImage.frame.origin.y, denterImage.bounds.size.width, denterImage.bounds.size.height - 200))
let mask = CAShapeLayer()
mask.anchorPoint = CGPointMake(0.5, 1.0)
mask.path = path.CGPath

denterImage.layer.mask = mask

let anim = CABasicAnimation(keyPath: "path")

anim.fromValue = path.CGPath
anim.toValue = UIBezierPath(rect: denterImage.bounds).CGPath
anim.duration =  1.5
anim.fillMode = kCAFillModeForwards
anim.removedOnCompletion = false

denterImage.layer.mask.addAnimation(anim, forKey: "anim")

我的建议是使用路径的描边而不是填充。

你画了一条路径(蓝线),从图层底部开始到顶部结束,水平居中,线宽相同作为图层宽度。
红色轮廓代表笔划轮廓。

你在 strokeEnd 属性 上播放一个从 0 到 1 的动画。

I made a playground 如果你想看看我是如何做到这一点的。

我更新了上面的link。
我放了代码以防你仍然无法进入游乐场

let aView = UIView(frame:CGRect(x:0 y:0 width:200 height:200))
aView.backgroundColor = UIColor.redColor() // the view that needs to be masked
let shapeLayer = CAShapeLayer()
shapeLayer.bounds = aView.bounds
let bezierPath = UIBezierPath()
bezierPath.moveToPoint(CGPoint(x: shapeLayer.bounds.width/2, y: shapeLayer.bounds.height))
bezierPath.addLineToPoint(CGPoint(x: shapeLayer.bounds.width/2, y: 0))
shapeLayer.path = bezierPath.CGPath
shapeLayer.fillColor = UIColor.clearColor().CGColor
shapeLayer.strokeColor = UIColor.redColor().CGColor
shapeLayer.lineWidth = shapeLayer.bounds.width
shapeLayer.position = CGPoint(x: aView.frame.width/2, y: aView.frame.height/2)
shapeLayer.strokeEnd = 1

let animation = CABasicAnimation(keyPath: "strokeEnd")
animation.fromValue = 0
animation.toValue = 1
animation.duration = 4
animation.timingFunction = CAMediaTimingFunction(name: kCAMediaTimingFunctionEaseInEaseOut)
shapeLayer.addAnimation(animation, forKey: "stroneAnimation")
shapeLayer.strokeEnd = 1
aView.layer.mask = shapeLayer

这将完全达到您想要的效果:

let path = UIBezierPath(rect: CGRectMake(0, imgEmptyBase.layer.frame.size.height, imgEmptyBase.layer.frame.size.width, imgEmptyBase.layer.frame.size.height))
let mask = CAShapeLayer()
mask.path = path.CGPath

imgEmptyBase.layer.mask = mask

let revealPath = UIBezierPath(rect: CGRectMake(0, 0, imgEmptyBase.layer.frame.size.width, imgEmptyBase.layer.frame.size.height))

let anim                = CABasicAnimation(keyPath: "path")
anim.fromValue          = path.CGPath
anim.toValue            = revealPath.CGPath
anim.duration           = 1.0
anim.fillMode           = kCAFillModeForwards
anim.removedOnCompletion = false

imgEmptyBase.layer.mask.addAnimation(anim, forKey: "anim")

一切都是关于使用正确的 "from" 和 "to" 值更改蒙版路径。例如:将初始遮罩路径设置为 CGRectMake(0, 0, imgEmptyBase.layer.frame.size.width, 0) 并将 revealPath 设置为 CGRectMake(0, 0, imgEmptyBase.layer.frame.size.width, imgEmptyBase.layer.frame.size.height) 将导致 "top to bottom" 显示效果。