UIView图层蒙版动画 [英] UIView Layer Mask Animate

查看:109
本文介绍了UIView图层蒙版动画的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在尝试对UIView上的遮罩层进行动画处理.

I am trying to animate the mask layer on a UIView.

基本上,此代码显示以下图像:

Basically this code displays the image below:

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

我希望它动画到从全屏到上方位置的切口的位置:

I want it to animate to that position of the cutout from being full screen to above position:

我尝试过UIView动画,但没有运气.既然我已经有了CAShapeLayer,那么我应该可以制作动画吗?

I tried UIView animation, and no luck. Since I already have a CAShapeLayer, I should be able to animate that?

编辑**

这是我尝试的动画代码,该代码不起作用:

Here's the animation code I tried, which didn't work:

 //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()


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


As per 'originaluser2's reply below, I have this:

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()

}

它制作动画;但是,我现在遇到两个问题: 1.动画过程中形状全部关闭,但如果在动画结束时合并在一起. (下面的屏幕截图)

It does the animation; However, I got two issues now: 1. Shape is all off during the animation, yet if come together at the end of the animation. (Screenshot below)

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

推荐答案

您将要在遮罩层的path属性上使用CABasicAnimation

这将使您可以将蒙版从给定路径动画化为另一个给定路径. Core Animation将自动为您插补中间步骤.

You'll want to use a CABasicAnimation on the path property of your mask layer

This will allow you to animate your mask from a given path, to another given path. Core Animation will automatically interpolate the intermediate steps for you.

类似的事情应该可以解决问题:

// 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()

结果:

需要注意的一件事是,Core Animation中似乎存在一个错误,即它无法正确地从包含矩形的路径到包含带有圆角半径的圆角rect的路径进行动画处理.我已经为此向Apple提交了错误报告.

One thing to note with this is that there appears to be a bug in Core Animation, where it's unable to correctly animate from a path that includes rectangle, to a path that includes a rounded rect with a corner radius. I have filed a bug report with Apple for this.

对此有一个简单的解决方法,即在原始路径上使用圆角半径可忽略不计的圆角矩形(对我来说,0.0001可以正常使用).有点骇人听闻-但是使用该应用程序时您不会注意到其中的区别.

There is a simple fix for this, which is to use a rounded rect with a corner radius of negligible value on the original path (0.0001 works okay for me). A bit hacky – but you can't notice the difference when using the app.

不幸的是,苹果公司认为这是预期行为".他们说:

Unfortunately, Apple considers this to be "expected behaviour". They said the following:

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

For the animation to render correctly, the animated paths should have the same number of elements/segments (ideally of the same type). Otherwise, there is no reasonable way to interpolate between the two.

例如,如果第一条路径包含四个元素,第二条路径包含六个元素,我们可以通过将当前时间的权重与前四个起点和终点进行平均,轻松地创建前四个点,但是不可能用通用的方法来计算第五点和第六点的中间位置.这就是为什么动画在拐角半径0.001(相同数量的元素)下效果很好,而在纯矩形路径(不同数量的元素)下效果不佳的原因.

For instance, if a first path has four elements and the second path has six elements, we can easily create the first four points by averaging the first four start and end points with a weight for current time, but it's impossible to come up with a general purpose way to calculate the intermediate positions for the fifth and sixth points. This is why the animation works just fine for corner radius 0.001 (the same number of elements), but fails for plain rectangular path (different number of elements).

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

I personally disagree, if you specify a rounded rect of corner radius 0 and then animate to a rounded rect with a corner radius > 0 – an incorrect animation is still obtained, even though both paths should have the "same number of elements". I suspect the reason this doesn't work is the internal implementation checks for a radius of 0, and tries to optimise by using a rectangular path with 4 elements instead, which is why it doesn't work.

我将在有空的时候提交另一个错误报告,以对此进行解释.

I will submit another bug report explaining this when I get the time.

您被迫解开manualWBMaskView了很多.别.您需要学习如何正确处理可选内容.每次您强制打开包装时,您的应用程序可能会崩溃.

You're force unwrapping your manualWBMaskView quite a bit. Don't. You need to learn how to properly deal with optionals. Every time you force unwrap something - your app could crash.

您也有几行是这样的:

let maskLayer: CAShapeLayer = CAShapeLayer()

这里的: CAShapeLayer不仅是不必要的-而且违反了惯例.您应该始终让Swift尽可能地推断出值的类型.

The : CAShapeLayer here is not only unnecessary - but goes against good practise. You should always let Swift infer the type of a value where it can.

这篇关于UIView图层蒙版动画的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆