Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

SwiftUI - UIViewRepresentable glitching when wrapping UIView with custom drawing

I've got an image that I made in PaintCode that I want to animate. PaintCode provides a drawing function for UIKit, not SwiftUI. So for testing I can implement it in UIKit with the following VC:

import UIKit

class ViewController: UIViewController {

    @IBOutlet weak var paintCode: PaintCodeView!
    @IBOutlet weak var slider: UISlider!

    override func viewDidLoad() {
        super.viewDidLoad()

    }

    @IBAction func sliderMoved(_ sender: Any) {
        paintCode.progress = CGFloat(slider.value)
    }

}

class PaintCodeView: UIView {

    private var _progress: CGFloat = 0.0

    var progress: CGFloat {
        set {
            if newValue < 0 {
                _progress = 0
            } else if newValue > 1 {
                _progress = 1
            } else {
                _progress = newValue
            }
            setNeedsDisplay()
        }
        get {
            return _progress
        }
    }

    override func draw(_ rect: CGRect) {
        LinkStyles.drawLogoAnimated(frame: self.bounds, resizing: .aspectFit, animationProgress: _progress)
    }

}

Correct animation

But if I try to wrap the same drawing UIView in a UIViewRepresentable to use in SwiftUI, it's not drawing it as expected, instead has a black background and glitching animation.

import SwiftUI
import UIKit

struct TestView: View {

    @State var progress: Float = 0.0

    var body: some View {
        VStack {
            Logo(animationProgress: $progress)
                .frame(width: 300, height: 300)
            Text("\(progress)")
            Slider(value: $progress)
                .padding(.horizontal)
        }
    }
}

struct Logo: UIViewRepresentable {

    @Binding var animationProgress: Float

    func makeUIView(context: Context) -> PaintCodeView {
        print("LinkLogo Make: \(animationProgress)")
        let view = PaintCodeView()
        view.progress = CGFloat(animationProgress)
        return view
    }

    func updateUIView(_ logoView: PaintCodeView, context: Context) {
        logoView.progress = CGFloat(animationProgress)
    }
}

class PaintCodeView: UIView {

    private var _progress: CGFloat = 0.0

    var progress: CGFloat {
        set {
            if newValue < 0 {
                _progress = 0
            } else if newValue > 1 {
                _progress = 1
            } else {
                _progress = newValue
            }
            setNeedsDisplay()
        }
        get {
            return _progress
        }
    }

    override func draw(_ rect: CGRect) {
        LinkStyles.drawLogoAnimated(frame: self.bounds, resizing: .aspectFit, animationProgress: _progress)
    }

}

Glitching animation

Any idea what I'm doing wrong?

like image 359
RogerTheShrubber Avatar asked Mar 05 '20 16:03

RogerTheShrubber


1 Answers

You need to set the background color to .clear in the UIView subclass (in below example in class MyWidgetView) in order to remove the black background.

import UIKit

class MyWidgetView: UIView {
    override init(frame: CGRect) {
        super.init(frame: frame)
        super.backgroundColor = UIColor.clear
    }
    
    required init?(coder: NSCoder) {
        fatalError()
    }
    
    override func draw(_ rect: CGRect) {
        PaintCodeClass.drawWidget(frame: self.bounds)
    }
}

struct ObstacleView: UIViewRepresentable {
    func makeUIView(context: Context) -> some UIView {
        ObstacleUIView()
    }
    
    func updateUIView(_ uiView: UIViewType, context: Context) {
        
    }
}
like image 176
Pete Avatar answered Oct 28 '22 20:10

Pete