SwiftUI在尝试在不同视图上重用UIViewRepresentable时丢失引用

beq87vna  于 2023-04-28  发布在  Swift
关注(0)|答案(2)|浏览(109)

我试图在SwiftUI上重用UIKit视图,并使用UIViewRepresentable。每当我点击representable时,我都想转到fullScreenCover并重用相同的UIView。不知何故,当我关闭fullscreenView时,UIView不见了。我已经尝试了几种方法,但我不能使它工作,可以有人指出我在正确的方向,是有什么我错过了看到?

struct ContentView: View {
   @State var isFullscreen: Bool = false
   /// Array of UIView objects
   var uiViewArray: [CustomUIView] = [CustomUIView(text: "1"), CustomUIView(text: "2"), CustomUIView(text: "3")]
   let cardWidth: CGFloat = 200
   let cardHeight: CGFloat = 200
   
   @StateObject var viewManager = ViewManager()

   var body: some View {
       return VStack {
           ScrollView {
               ForEach(uiViewArray, id: \.id) { uiView in
                   LabelViewRepresentable(customUIView: uiView)
                       .frame(width: cardWidth,
                              height: cardHeight)
                       .onTapGesture(count: 2) {
                           viewManager.selectedFullscreenView = uiView
                           isFullscreen.toggle()
                       }
               }
           }
       }
       .background(Color.gray)
       .fullScreenCover(isPresented: $isFullscreen,
                     content: {
           FullScreenView(isFullscreen: $isFullscreen,
                          uiView: viewManager.selectedFullscreenView)
       })
    
   }
}
struct FullScreenView: View {
    @Binding var isFullscreen: Bool
    var uiView: CustomUIView?
         
    var body: some View {
        VStack {
            Button(action: {
                isFullscreen.toggle()
            }, label: {
                Text("Close")
            })
            if uiView != nil {
                LabelViewRepresentable(customUIView: uiView!)
            }
        }
    }
}
struct LabelViewRepresentable: UIViewRepresentable {
    var customUIView: CustomUIView
    
    init(customUIView: CustomUIView) {
        self.customUIView = customUIView
    }

    func makeUIView(context: Context) -> CustomUIView {
       uiView.backgroundColor = .green
       return customUIView
    }

    func updateUIView(_ uiView: CustomUIView, context: Context) { }
}
class CustomUIView: UIView {
    var text: String
    var id = UUID().uuidString
    
    init(text: String) {
        self.text = text
        super.init(frame: .zero)
        let label = UILabel()
        label.frame = .init(origin: .zero,
                            size: CGSize(width: 100, height: 100))
        label.text = self.text
        self.addSubview(label)
    }
    
    required init?(coder _: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }
}

class ViewManager: ObservableObject  {
    var selectedFullscreenView: CustomUIView?
}
bsxbgnwa

bsxbgnwa1#

UIView只能添加到视图层次结构中一次。一旦它被添加到全屏视图中,它就被从原始层次结构中取出,并且当全屏视图被解除时,它没有信号将自己添加回原始层次结构中。
您可以通过在原始ScrollView中有条件地显示它来避免此问题。请注意,我添加了一个Spacer来占用它的空间并保留滚动位置,而真实的的UIView则从层次结构中省略。

ForEach(uiViewArray, id: \.id) { uiView in
    Group {
        if !isFullscreen {
            LabelViewRepresentable(customUIView: uiView)
        } else {
            Spacer()
        }
    }
    .frame(width: cardWidth,
           height: cardHeight)
    .onTapGesture(count: 2) {
        viewManager.selectedFullscreenView = uiView
        isFullscreen.toggle()
    }
}
bqujaahr

bqujaahr2#

makeUIView需要初始化它,e.g的。

func makeUIView(context: Context) -> CustomUIView {
       let uiView = CustomUIView()
       uiView.backgroundColor = .green
       return uiView
    }

您还需要实现updateUIView以使用结构体的var来更新uiView的任何更改,例如:g的。

let text: String

func updateUIView(_ uiView: CustomUIView, context: Context) {
    if uiView.text != text {
        uiView.text = text
    }
}

可以将UIViewRepresentable看作是一个不断变化的配置值,您可以使用它来更新同一个UIView对象。SwiftUI会根据UIView对象在View层次结构中的位置(称为其标识)跟踪要配置的UIView对象,并将其传递给updateUIView,这样您就不需要自己保存它了。

相关问题