尝试使用 CALayers 为水龙头的水滴设置动画

Posted

技术标签:

【中文标题】尝试使用 CALayers 为水龙头的水滴设置动画【英文标题】:Trying to animate a drop from a faucet with CALayers 【发布时间】:2018-09-11 19:19:57 【问题描述】:

我正在尝试创建一个 UIView 子类,该子类显示一个水龙头,其水滴不断增长然后下降。我对不同部分进行的实验越多,我就越感到困惑。

我创建了两个图形:

我创建了一个 UIView 类:

class ValvebeatView: UIView 
    var faucet = CALayer()
    var drip = CALayer()

    func _init() 
        self.faucet.contents = #imageLiteral(resourceName: "faucet").cgImage
        self.drip.contents = #imageLiteral(resourceName: "droplet").cgImage
        self.layer.insertSublayer(self.drip, above: nil)
        self.layer.insertSublayer(self.faucet, above: self.drip)
    

    override init(frame: CGRect) 
        super.init(frame: frame)
        self._init()
    

    required init(coder aDecoder: NSCoder) 
        super.init(coder: aDecoder)!
        self._init()
    

    override func layoutSubviews() 
        super.layoutSubviews()
        self.faucet.frame = self.bounds
        self.drip.frame = self.bounds
    

    func startDrop() 

    

如果我在我的应用程序中添加这个视图,我会得到如下所示的内容:

这恰到好处。但是,当我尝试尝试改变水滴的外观时,没有任何效果。到目前为止我已经尝试/学到了什么:

设置drip.contentScale 似乎没有任何作用。文档听起来好像这只是一个提示? 我玩过contentsRect,这似乎改变了它,但在阅读文档后,它似乎表明它决定了显示的放置图像的子部分。我想展示所有的下降,我只想从小处着手,让它膨胀,然后切换到向下平移。 各种变换选项(缩放然后平移)似乎是正确的处理方式。但这也不会产生正确的结果。例如,如果我为self.valvebeatView.drip.transform = CATransform3DMakeScale(0.1, 0.1, 1) 设置了轻击手势,它会暂时膨胀 10 倍,然后恢复为原始大小。但更奇怪的是,如果我改为使用self.valvebeatView.drip.transform = CATransform3DMakeScale(10.0, 10.0, 1),它会做同样的事情?!?!?为什么它至少没有收缩然后恢复到原来的形状?

我想知道是不是因为我的重力设置为默认值(即调整大小)。但是,当我将其更改为中心时,原来的水滴已经过大了。

我的问题是,我想使用哪些钩子(变换、位置等?)动画我的水滴从小规模增长到正常,然后向下下降。

【问题讨论】:

【参考方案1】:

假设您确实希望坚持使用图层和图层动画来执行此操作,而不是使用更简单的视图和视图动画方法。

然后在您列出的相当古怪的想法中,只更改transform 并且可能还更改position(如果这个想法也是移动下降)是正确的。您需要了解 CABasicAnimation。要以一种很好的协调方式将水滴的增长与水滴的下降结合起来,请使用 CAAnimationGroup。

【讨论】:

但是如果这个想法是创造一个稳定的水滴流,这可能是一个 CAEmitter 的工作。 我对如何使用两个堆叠的图像视图来做到这一点相当有信心。然后只需为变换或什至下降的帧/边界设置动画。我认为图层是做事的“首选”方式。我真正的挫败感是我在应用任何动画类之前很久就更改变换的经验(迄今为止我已经使用了很多,但通常只用于旋转)。 这不会改变我的答案。【参考方案2】:
 func startDrop() 

    self.drip.contentsGravity = kCAGravityCenter
    let center = CGPoint.init(x: self.frame.width / 2.0, y: self.frame.height / 2.0)
    let scaleAnimation = CAKeyframeAnimation.init(keyPath: "contentsScale")
    scaleAnimation.values = [3, 1, 1 ]
    scaleAnimation.keyTimes = [0,0.2, 1]
    scaleAnimation.duration = 3
    scaleAnimation.isRemovedOnCompletion = false
    scaleAnimation.repeatCount = Float.greatestFiniteMagnitude
    let positionAnimation = CAKeyframeAnimation.init(keyPath: "position")
    positionAnimation.values = [center  , center, CGPoint.init(x:center.x ,y:center.y * 2) ]
    positionAnimation.keyTimes = [0,0.2, 1]
    positionAnimation.duration = 3
    positionAnimation.repeatCount = Float.greatestFiniteMagnitude
    positionAnimation.isRemovedOnCompletion = false

    self.drip.add(scaleAnimation, forKey: "scale")
    self.drip.add(positionAnimation, forKey: "pos")


【讨论】:

以上是关于尝试使用 CALayers 为水龙头的水滴设置动画的主要内容,如果未能解决你的问题,请参考以下文章

动画 calayers 不断跟随手指位置

UIView 动画与 CALayers

水滴下落字符动画

iphone - 创建像用户位置蓝色大理石水滴这样的动画

SKSpriteNode 动画渐变

CSS 3.0结合SVG实现水滴穿透加载动画