Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/ios/95.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Ios 将自定义可设置动画的UIView属性与其他动画同步_Ios_Swift_Core Animation_Calayer_Uiviewanimation - Fatal编程技术网

Ios 将自定义可设置动画的UIView属性与其他动画同步

Ios 将自定义可设置动画的UIView属性与其他动画同步,ios,swift,core-animation,calayer,uiviewanimation,Ios,Swift,Core Animation,Calayer,Uiviewanimation,我有一个UIView子类,它有一个自定义的可设置动画的属性,与其他视图上的其他(内置)UIView属性一起设置动画。我遇到的问题是,这个自定义属性在动画期间似乎与布局的其余部分稍微不同步 下面是一个简单的例子来说明我的意思: 蓝色方块使用内置的transform属性设置动画,而红色方块则在另一个(静止的)UIView中绘制,并通过自定义属性drawFrame设置动画。两个属性的动画都匹配,因此,理论上,两个矩形应该始终彼此垂直对齐 下面是上面示例的代码。要执行,只需启动一个新的单视图应用程序项

我有一个
UIView
子类,它有一个自定义的可设置动画的属性,与其他视图上的其他(内置)
UIView
属性一起设置动画。我遇到的问题是,这个自定义属性在动画期间似乎与布局的其余部分稍微不同步

下面是一个简单的例子来说明我的意思:

蓝色方块使用内置的
transform
属性设置动画,而红色方块则在另一个(静止的)
UIView
中绘制,并通过自定义属性
drawFrame
设置动画。两个属性的动画都匹配,因此,理论上,两个矩形应该始终彼此垂直对齐

下面是上面示例的代码。要执行,只需启动一个新的单视图应用程序项目并替换
ViewController.swift
的内容即可

import UIKit

class ViewController: UIViewController {

    let viewA = UIView(frame: CGRect(x: 50, y: 50, width: 100, height: 100))
    let viewB = CustomAnimatedPropertyView(frame: CGRect(x: 50, y: 150, width: 200, height: 100))

    override func viewDidLoad() {
        super.viewDidLoad()
        view.addSubview(viewA); viewA.backgroundColor = UIColor.blue
        view.addSubview(viewB); viewB.backgroundColor = UIColor.clear
        animate()
    }

    func animate() {
        viewA.transform = CGAffineTransform.identity
        viewB.drawFrame = CGRect(x: 0, y: 0, width: 100, height: 100)
        UIView.animate(withDuration: 2.0, delay: 1.0, options: [], animations: {
            self.viewA.transform = CGAffineTransform.identity.translatedBy(x: 100, y: 0.0)
            self.viewB.drawFrame = CGRect(x: 100, y: 0, width: 100, height: 100)
        })
        DispatchQueue.main.asyncAfter(deadline: DispatchTime.now() + 3) { self.animate() }
    }
}

class CustomAnimatedPropertyView: UIView {

    @objc dynamic var drawFrame: CGRect = CGRect.zero {
        didSet {
            guard let layer = layer as? CustomAnimatedPropertyLayer else { fatalError() }
            layer.drawFrame = drawFrame
        }
    }

    override public class var layerClass: AnyClass {
        return CustomAnimatedPropertyLayer.self
    }

    override public func action(for layer: CALayer, forKey event: String) -> CAAction? {
        if event == #keyPath(CustomAnimatedPropertyLayer.drawFrame),
           let action = super.action(for: layer, forKey: #keyPath(backgroundColor)) as? CAAnimation,
           let animation: CABasicAnimation = (action.copy() as? CABasicAnimation) {
            animation.keyPath = #keyPath(CustomAnimatedPropertyLayer.drawFrame)
            animation.fromValue = (layer as! CustomAnimatedPropertyLayer).drawFrame
            animation.toValue = drawFrame
            layer.add(animation, forKey: #keyPath(CustomAnimatedPropertyLayer.drawFrame))
            return animation
        }
        return super.action(for: layer, forKey: event)
    }

    override func draw(_ layer: CALayer, in ctx: CGContext) {
        guard let customLayer = layer as? CustomAnimatedPropertyLayer else { super.draw(layer, in: ctx); return }
        ctx.setFillColor(UIColor.red.cgColor)
        ctx.fill(customLayer.drawFrame)
        usleep(20 * 1000) // <- To exacerbate the synchronization issue
    }
}

class CustomAnimatedPropertyLayer: CALayer {

    @NSManaged var drawFrame: CGRect
    override class func needsDisplay(forKey key: String) -> Bool {
        return super.needsDisplay(forKey: key) || key == #keyPath(drawFrame)
    }
}
导入UIKit
类ViewController:UIViewController{
让viewA=UIView(帧:CGRect(x:50,y:50,宽度:100,高度:100))
let viewB=CustomAnimatedPropertyView(帧:CGRect(x:50,y:150,宽度:200,高度:100))
重写func viewDidLoad(){
super.viewDidLoad()
view.addSubview(viewA);viewA.backgroundColor=UIColor.blue
view.addSubview(viewB);viewB.backgroundColor=UIColor.clear
制作动画()
}
func animate(){
viewA.transform=CGAffineTransform.identity
viewB.drawFrame=CGRect(x:0,y:0,宽度:100,高度:100)
UIView.animate(持续时间:2.0,延迟:1.0,选项:[],动画:{
self.viewA.transform=CGAffineTransform.identity.translatedBy(x:100,y:0.0)
self.viewB.drawFrame=CGRect(x:100,y:0,宽度:100,高度:100)
})
DispatchQueue.main.asyncAfter(截止日期:DispatchTime.now()+3){self.animate()}
}
}
类CustomAnimatedPropertyView:UIView{
@objc动态变量drawFrame:CGRect=CGRect.zero{
迪塞特{
guard let layer=层为?CustomAnimatedPropertyLayer else{fatalError()}
layer.drawFrame=drawFrame
}
}
重写公共类var layerClass:AnyClass{
返回CustomAnimatedPropertyLayer.self
}
覆盖公共函数操作(对于层:CALayer,forKey事件:String)->CAAction{
如果事件=#关键路径(CustomAnimatedPropertyLayer.drawFrame),
让action=super.action(对于:层,forKey:#keyPath(backgroundColor))作为动画,
让动画:CABasicAnimation=(action.copy()作为?CABasicAnimation){
animation.keyPath=#keyPath(CustomAnimatedPropertyLayer.drawFrame)
animation.fromValue=(图层为!CustomAnimatedPropertyLayer)。drawFrame
animation.toValue=drawFrame
添加(动画,forKey:#关键路径(CustomAnimatedPropertyLayer.drawFrame))
返回动画
}
返回super.action(for:layer,forKey:event)
}
覆盖func绘图(layer:CALayer,在ctx:CGContext中){
guard let customLayer=图层为?CustomAnimatedPropertyLayer else{super.draw(图层,in:ctx);返回}
ctx.setFillColor(UIColor.red.cgColor)
ctx.fill(customLayer.drawFrame)
usleep(20*1000)//Bool{
返回super.needsDisplay(forKey:key)| | key==#keyPath(drawFrame)
}
}
我尝试过很多不同的解决方案,但都没有效果……我认为可以使用
CADisplayLink
或类似的解决方案来解决这个问题,但我更倾向于避免涉及重大代码重构的解决方案


关于如何解决这个问题有什么想法吗?提前感谢您的回答。

我认为您的问题没有通用的解决方案,动画的抖动来自不同的类型。转换动画应该比简单的标量值动画更复杂

然而,我看到了以下几种可能的方法来解决snchronization问题。我有几个建议供您选择

  • 如果您的两个动画确实是翻译,则都应表示为翻译:
  • 最好的方法可能是将两个层放在一个普通的超级层中,然后移动超级层
  • 或者对两个动画使用相同的动画属性,例如,通过它们的
    转换
    属性进行转换。两个层都应使用通用的基本动画
  • 如果确实需要一个动画的自定义可设置动画的属性,则应尝试使用自定义属性来表示另一个动画。如果两个动画都基于不同的自定义属性,则可以使用动画组,这样可以改进两个动画的同步。(注意:如果动画基于公共特性,则不能使用组,因为它还将为另一层上的公共特性设置动画。)
  • 如果两个动画值严格连接,您可以创建一个显示两个层内容的组合层。它只有一个可设置动画的属性,可以适当更改其表示形式

  • 不幸的是,无可否认,我的建议非常笼统,但为了能够给出更具体的路径,我必须对具体问题有更多的了解。

    输入代码viewDidAppear@Sh_Khan同样的结果。我还应该指出,上面的示例代码是我正在处理的实际生产代码的一个非常简化的版本视图具有不同的Xposition@Sh_Khan我不知道你为什么这么说……蓝色视图是一个完美的100x100px正方形,它被转换为右100px。红色视图是一个200x100px的矩形,它根本不移动-只有在它里面绘制的矩形得到更新,从它的初始位置向右正好100px。原点X两个视图的坐标相同。@Kevinosaurio
    drawFrame
    的值在target
    ui视图中表示