UIView图层蒙版动画

Giz*_*odo 6 mask layer uiview cashapelayer swift

我试图在UIView上设置遮罩层的动画.

基本上这段代码显示如下图片:

let bounds: CGRect = self.manualWBMaskView!.bounds
let maskLayer: CAShapeLayer = CAShapeLayer()
maskLayer.frame = bounds
maskLayer.fillColor = UIColor.blackColor().CGColor
let screenWith  : CGFloat = UIScreen.mainScreen().bounds.width
let roundedRectFrame : CGRect = CGRectMake(self.manualWBMaskView!.bounds.midX - (screenWith/4), self.manualWBMaskView!.bounds.midY - (screenWith/4), screenWith/2, screenWith/2)
let path: UIBezierPath = UIBezierPath(roundedRect:roundedRectFrame, cornerRadius:10  )
path.appendPath(UIBezierPath(rect: bounds))
maskLayer.path = path.CGPath
maskLayer.fillRule = kCAFillRuleEvenOdd
self.manualWBMaskView!.layer.mask = maskLayer
Run Code Online (Sandbox Code Playgroud)

在此输入图像描述

我想让它从全屏到以上位置动画到切口的位置:

在此输入图像描述

我试过UIView动画,没有运气.既然我已经有一个CAShapeLayer,我应该能够动画那个?

编辑**

这是我试过的动画代码,它不起作用:

 //Before Animation Make the Mask fill the whole view:
    self.manualWBMaskView!.layer.mask = self.manualWBMaskView!.bounds

    var duration: NSTimeInterval = 0.8

    CATransaction.begin()
    CATransaction[kCATransactionAnimationDuration] = Int(duration)
    self.manualWBMaskView!.layer.mask = CGRectMake(self.manualWBMaskView!.bounds.midX - (screenWith/4), self.manualWBMaskView!.bounds.midY - (screenWith/4), screenWith/2, screenWith/2)
    CATransaction.commit()
Run Code Online (Sandbox Code Playgroud)

根据'originaluser2的回复,我有这个:

func presentMaskScreenWithAnimation () {
                let bounds: CGRect = self.manualWBMaskView!.bounds
                let maskLayer: CAShapeLayer = CAShapeLayer()
                maskLayer.frame = bounds
                maskLayer.fillColor = UIColor.blackColor().CGColor
                let screenWith  : CGFloat = UIScreen.mainScreen().bounds.width
                let roundedRectFrame : CGRect = self.manualWBMaskView.bounds
                let path: UIBezierPath = UIBezierPath(roundedRect:roundedRectFrame, cornerRadius:0  )
                path.appendPath(UIBezierPath(rect: bounds))
                maskLayer.path = path.CGPath
                maskLayer.fillRule = kCAFillRuleEvenOdd
                self.manualWBMaskView!.layer.mask = maskLayer

       // define your new path to animate the mask layer to
        let screenWith2  : CGFloat = UIScreen.mainScreen().bounds.width
        let roundedRectFrame2 : CGRect = CGRectMake(self.manualWBMaskView!.bounds.midX - (screenWith2/4), self.manualWBMaskView!.bounds.midY - (screenWith2/4), screenWith2/2, screenWith2/2)

        let path2 = UIBezierPath(roundedRect:roundedRectFrame2, cornerRadius:10  )

        // create new animation
        let anim = CABasicAnimation(keyPath: "path")    

        // from value is the current mask path
        anim.fromValue = maskLayer.path

        // to value is the new path
        anim.toValue = path2.CGPath

        // duration of your animation
        anim.duration = 5.0

        // custom timing function to make it look smooth
        anim.timingFunction = CAMediaTimingFunction(name: kCAMediaTimingFunctionEaseInEaseOut)

        // add animation
        maskLayer.addAnimation(anim, forKey: nil)

        // update the path property on the mask layer, using a CATransaction to prevent an implicit animation
        CATransaction.begin()
        CATransaction.setDisableActions(true)
           maskLayer.path = path2.CGPath
           maskLayer.fillRule = kCAFillRuleEvenOdd
        CATransaction.commit()

}
Run Code Online (Sandbox Code Playgroud)

它做动画; 但是,我现在遇到两个问题:1.动画期间形状完全关闭,但如果在动画结束时聚集在一起.(下面的截图)

  1. 面具倒置了.它在形状内部可见,但在其周围透明.我需要相反的.里面的形状是透明的.

在此输入图像描述

Ham*_*ish 22

您将要CABasicAnimationpath遮罩层的属性上使用a

这将允许您将蒙版从给定路径动画到另一个给定路径.核心动画将自动为您插入中间步骤.

像这样的东西应该做的伎俩:

// define your new path to animate the mask layer to
let path = UIBezierPath(roundedRect: CGRectInset(view.bounds, 100, 100), cornerRadius: 20.0)
path.appendPath(UIBezierPath(rect: view.bounds))

// create new animation
let anim = CABasicAnimation(keyPath: "path")

// from value is the current mask path
anim.fromValue = maskLayer.path

// to value is the new path
anim.toValue = path.CGPath

// duration of your animation
anim.duration = 5.0

// custom timing function to make it look smooth
anim.timingFunction = CAMediaTimingFunction(name: kCAMediaTimingFunctionEaseInEaseOut)

// add animation
maskLayer.addAnimation(anim, forKey: nil)

// update the path property on the mask layer, using a CATransaction to prevent an implicit animation
CATransaction.begin()
CATransaction.setDisableActions(true)
maskLayer.path = path.CGPath
CATransaction.commit()
Run Code Online (Sandbox Code Playgroud)

结果:

在此输入图像描述

有一点需要注意的是,Core Animation中似乎存在一个错误,它无法从包含矩形的路径正确动画到包含带圆角半径的圆角矩形的路径.我已经向Apple提交了一份错误报告.

有一个简单的解决方法,就是在原始路径上使用圆角矩形,角半径可忽略不计(0.0001对我来说没问题).有点hacky - 但你不能注意到使用应用程序时的差异.


来自Apple的错误报告回复

不幸的是,Apple认为这是"预期行为".他们说了以下几点:

要使动画正确渲染,动画路径应具有相同数量的元素/段(理想情况下为相同类型).否则,没有合理的方法在两者之间进行插值.

例如,如果第一条路径有四个元素而第二条路径有六个元素,我们可以通过平均前四个起点和终点以及当前时间的权重来轻松创建前四个点,但是不可能得到一个用于计算第五和第六点的中间位置的通用方法.这就是为什么动画在角半径0.001(相同数量的元素)下工作得很好,但对于普通矩形路径(不同数量的元素)则失败.

我个人不同意,如果指定圆角半径为0的圆角矩形,然后动画为圆角矩形,角半径> 0 - 仍然会获得不正确的动画,即使两个路径都应具有"相同数量的元素".我怀疑这不起作用的原因是内部实现检查半径为0,并尝试通过使用具有4个元素的矩形路径进行优化,这就是为什么它不起作用.

当我有空的时候,我会提交另一个错误报告来解释这个.


其他几件事......

你很有力地解开你manualWBMaskView的东西.别.您需要学习如何正确处理选项.每次你强行解开东西 - 你的应用程序可能会崩溃.

你也有这样几行:

let maskLayer: CAShapeLayer = CAShapeLayer()
Run Code Online (Sandbox Code Playgroud)

: CAShapeLayer不仅是不必要的 - 而且违背了良好的做法.你应该总是让Swift推断它可以的值的类型.