UIViewRepresentable animations

I've tried to animate custom UIViewRepresentable with SwitfUI animations, but it doesn't work. It just sets value without interpolation. What should i do to use interpolation values in UIKit views?

My example shows two "progress bars" red one is UIKit view, blue one is SwiftUI version. Sliders controls value directly, randomize button changes value to random with 5s animation.

When I press button SwiftUI progress bar animates exactly as it should, but UIKit's one just jumps to final position.

Set block of animatableData inside Animatable extension not called.

How can I use SwiftUI animation value interpolations for UIKit?

import SwiftUI
import UIKit

class UIAnimationView: UIView {
    
    var progress: CGFloat = 0.5 {
        didSet {
            
            if self.progressConstraint != nil, self.innerView != nil {
                self.removeConstraint(self.progressConstraint!)
            }
            let progressConstraint = NSLayoutConstraint(
                item: innerView!,
                attribute: .trailing,
                relatedBy: .equal,
                toItem: self,
                attribute: .trailing,
                multiplier: min(1.0, max(0.0001, progress)),
                constant: 0
            )
            self.addConstraint(progressConstraint)
            self.progressConstraint = progressConstraint
            
            self.layoutIfNeeded()
        }
    }
    var innerView: UIView?
    
    private var progressConstraint: NSLayoutConstraint?

    public override init(frame: CGRect) {
        super.init(frame: frame)
        self.performInit()
    }
    
    public required init?(coder: NSCoder) {
        super.init(coder: coder)
        self.performInit()
    }
    
    private func performInit() {
        let innerView = UIView()
        innerView.translatesAutoresizingMaskIntoConstraints = false
        
        self.addSubview(innerView)
        
        self.leadingAnchor.constraint(equalTo: innerView.leadingAnchor).isActive = true
        self.topAnchor.constraint(equalTo: innerView.topAnchor).isActive = true
        self.bottomAnchor.constraint(equalTo: innerView.bottomAnchor).isActive = true
        
        let progressConstraint = NSLayoutConstraint(
            item: innerView,
            attribute: .trailing,
            relatedBy: .equal,
            toItem: self,
            attribute: .trailing,
            multiplier: progress,
            constant: 0
        )
        self.progressConstraint = progressConstraint
        self.addConstraint(progressConstraint)
        
        self.innerView = innerView
        self.innerView!.backgroundColor = UIColor.red
        self.backgroundColor = UIColor.black
    }
    
}

struct AnimationTest: UIViewRepresentable {
    
    var progress: CGFloat
    
    typealias UIViewType = UIAnimationView
    
    func updateUIView(_ uiView: UIAnimationView, context: Context) {
        print("progress: \(progress) \(context.transaction.isContinuous)")
        uiView.progress = progress
    }

    func makeUIView(context: Context) -> UIAnimationView {
        let view = UIAnimationView()
        view.progress = progress
        return view
    }
}

extension AnimationTest: Animatable {
    var animatableData: CGFloat {
        get {
            return progress
        }
        set {
            print("Animation \(newValue)")
            progress = newValue
        }
    }
}

struct AnimationDebug: View {
    
    @State var progress: CGFloat = 0.75
    
    var body: some View {
        
        VStack {
            AnimationTest(progress: progress)
            
            Spacer()
            
            VStack {
                Slider(value: $progress, in: 0...1) {
                    Text("Progress")
                }
            }
            
            GeometryReader { gr in
                Color.blue
                    .frame(
                        width: gr.size.width * progress,
                        height: 48)
            }
            .frame(height: 48)
            
            Button("Randomize") {
                withAnimation(Animation.easeInOut(duration: 5)) {
                    progress = CGFloat.random(in: 0...1)
                }
            }
        }
    }
}

struct AnimationTest_Previews: PreviewProvider {
    
    static var previews: some View {
        AnimationDebug()
    }
}

BUMP - I have the exact same problem, how should we address this?

Same here!

UIViewRepresentable animations
 
 
Q