swiftuiuiviewrepresentable

Can't use UIViewRepresentable based on UIView more than once in the same View


When I try to place several UIViewRepresentable views to ContentView, it's shown only the last one. Here is the code:

struct ContentView: View {
        
    @State var customView = UIView()
    
    var body: some View {
        NavigationView {
            VStack {
                CustomView(view: customView)
                
                CustomView(view: customView)
                    .offset(x: 100, y: 0)
            }
            .navigationTitle("Test UIViewRepresentable")
            .navigationBarTitleDisplayMode(.inline)
            .toolbar {
                ToolbarItem(placement: .navigationBarTrailing) {
                    Button {
                        makeNewView()
                    } label: {
                        Image(systemName: "plus")
                    }
                }
            }
        }
    }
    private func makeNewView() {
        let path = UIBezierPath(rect: CGRect(x: 0, y: 0, width: 50, height: 50))
        let layer = CAShapeLayer()
        layer.path = path.cgPath
        layer.fillColor = CGColor(red: 1.0, green: 0.0, blue: 0.0, alpha: 1.0)
        customView.layer.addSublayer(layer)
    }
}

I removed model and viewmodel here to simplify the code. And here is the UIView representable:

struct CustomView: UIViewRepresentable {
    
    var view: UIView
    
    func makeUIView(context: Context) -> UIView {
        return view
    }
    
    func updateUIView(_ uiView: UIView, context: Context) {}
}

The second view is shifted down, so the first one is in its place but not shown. What should I do to get both views shown in ContentView?


Solution

  • Instead of creating @State var customView = UIView() in ContentView create this in CustomView and use in ContentView Multiple Times like this

    UIViewRepresentable

    struct CustomView: UIViewRepresentable {
        
        var view = UIView(frame: CGRect(x: 0, y: 0, width: 100, height: 100))
        
        func makeUIView(context: Context) -> UIView {
            let path = UIBezierPath(rect: CGRect(x: 0, y: 0, width: 100, height: 100))
            let layer = CAShapeLayer()
            layer.path = path.cgPath
            layer.fillColor = CGColor(red: 1.0, green: 0.0, blue: 0.0, alpha: 1.0)
            view.layer.addSublayer(layer)
            return view
        }
        
        func updateUIView(_ uiView: UIView, context: Context) {}
    }
    

    SwiftUI View

    struct ContentView: View {
       
        var body: some View {
            NavigationView {
                VStack {
                    CustomView()
                    
                    CustomView()
                        .offset(x: 100, y: 0)
                }
                .navigationTitle("Test UIViewRepresentable")
                .navigationBarTitleDisplayMode(.inline)
                .toolbar {
                    ToolbarItem(placement: .navigationBarTrailing) {
                        Button {
                           // CustomView()
                        } label: {
                            Image(systemName: "plus")
                        }
                    }
                }
            }
            
        }
        
    }
    

    enter image description here