SwiftUI - 使用自定义绘图包装 UIView 时出现 UIViewRepresentable 故障

Posted

技术标签:

【中文标题】SwiftUI - 使用自定义绘图包装 UIView 时出现 UIViewRepresentable 故障【英文标题】:SwiftUI - UIViewRepresentable glitching when wrapping UIView with custom drawing 【发布时间】:2020-03-05 16:54:03 【问题描述】:

我有一张在 PaintCode 中制作的图像,我想对其进行动画处理。 PaintCode 为 UIKit 提供了绘图功能,而不是 SwiftUI。因此,为了进行测试,我可以使用以下 VC 在 UIKit 中实现它:

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)
    


但是,如果我尝试将相同的绘图 UIView 包装在 UIViewRepresentable 中以在 SwiftUI 中使用,它不会按预期绘制它,而是具有黑色背景和闪烁动画。

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)
    


知道我做错了什么吗?

【问题讨论】:

您好 RogerTheShrubber,我遇到了与黑色背景相同的问题,并且在遇到困难时已向 PaintCode 寻求帮助。你找到解决办法了吗? 【参考方案1】:

您需要在 UIView 子类中将背景颜色设置为 .clear(在下面的 class MyWidgetView 示例中),以去除黑色背景。

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) 
        
    

【讨论】:

以上是关于SwiftUI - 使用自定义绘图包装 UIView 时出现 UIViewRepresentable 故障的主要内容,如果未能解决你的问题,请参考以下文章

SwiftUI - 在视图中包装 Button,以创建自定义按钮

自定义属性包装器无法准确反映我在 SwiftUI 中的 TextField 的状态,知道为啥吗?

如何在 SwiftUI 中使用 UIViewController 和 UIView?

SwiftUI 接收自定义事件

如何在 SwiftUI 视图中包装 UIBarButtonItem?

带有 UIViewRepresentable 的 SwiftUI 自定义文本字段 ObservableObject 和推送视图的问题