如何访问 LazyVStack 中特定索引处的 SwiftUI Button 实例(UIHostingController 的 rootView)?

问题描述 投票:0回答:1

我有一个自定义 SwiftUI 容器视图,其中包含一组 SwiftUI 按钮。

SwiftUI 按钮包含一个 UIKit UIView,我需要由主 UIViewConroller 使用。代码如下所示:

    public struct ContainerView: View {
        public var body: some View {
           LazyVStack {
           ForEach(viewModel.buttonViewModels, id:\.self) { buttonViewModel in 
           CustomButton(buttonViewModel)
       }
     }
    }
   }

    public class CustomButton: View {
    public var backgroundUIView = BackgroundUIView()
    public var body: some View {
        Button(action: viewModel.tapEvent), label: {
           ZStack {
               backgroundUIView
               Text(viewModel.title)
           } 
        }
    }


    public BackgroundUIView: UIViewRepresentable {
    func makeUIView(context: Context) -> UIView {
        let view = UIView()
        view.backgroundColor = .blue
        return view
    }


    public CustomHostingController: UIHostingController<ContainerView> {
        public var containerViewModel: ContainerViewModel

        public init?(containerViewModel: ContainerViewModel) {
           self.containerVieModel = containerViewModel
           super.init(rootView: ContainerView())
        }
   }

在 CustomHostingController 中如何访问特定索引处的 CustomButton 我想要这样的东西。

extension CustomHostingController {
    func getButtonAtIndex(index: Int) -> CustomButton {
       rootView.body.subviews[index]
    }
}

我需要在 CustomHostingController 中的特定索引处找到 CustomButton 实例。

尝试找到一种方法在 ContainerView 中的特定索引处查找 Swiftui 按钮。喜欢

    extension CustomHostingController {
        func getButtonAtIndex(index: Int) -> CustomButton {
           rootView.body.*subviews[index]*
        }
    }

与 SwiftUI 中的 UIKit 不同,没有办法做到这一点

subViews[at index]
。如何访问特定索引处的 CustomButton 实例?

我需要访问 CustomButton,因为 CustomHostingController 是 UIKit UIViewController 的子视图控制器,并且我想呈现第三方提供的 Popover 控制器(UIKit 实现),它需要 UIView 作为呈现它的源视图。 第三方 Popover 控制器初始化程序需要 UIView 或 UIButton 作为参数 sourceView,以便 Popover 控制器的箭头指针可以指向 UIView 或 UIButton。

所以我需要使用 customButton 实例,如下所示:

'[[ThirdPartyPopoverController alloc] initWithDescription: @"提供测试 Coachmark" fromSourceView:customButton.backgroundUIView];`

swift objective-c xcode swiftui instance
1个回答
0
投票

您需要将 UIView(在本例中为 backgroundUIView)公开给 CustomHostingController。这可以通过将回调传递给 CustomButton 来完成,这可以让托管控制器知道何时创建新的 UIView。

试试这个:

public struct BackgroundUIView: UIViewRepresentable {
    var onUIViewCreated: ((UIView) -> Void)?

    func makeUIView(context: Context) -> UIView {
        let view = UIView()
        view.backgroundColor = .blue
        onUIViewCreated?(view)
        return view
    }

    func updateUIView(_ uiView: UIView, context: Context) {}
}

public struct CustomButton: View {
    public var viewModel: ButtonViewModel
    public var index: Int
    public var onUIViewCreated: ((Int, UIView) -> Void)?

    public var body: some View {
        Button(action: viewModel.tapEvent) {
            ZStack {
                BackgroundUIView(onUIViewCreated: { view in
                    onUIViewCreated?(index, view)
                })
                Text(viewModel.title)
            }
        }
    }
}

public struct ContainerView: View {
    @ObservedObject var viewModel: ContainerViewModel
    var onUIViewCreated: ((Int, UIView) -> Void)?

    public var body: some View {
        LazyVStack {
            ForEach(viewModel.buttonViewModels.indices, id: \.self) { index in
                CustomButton(viewModel: viewModel.buttonViewModels[index],
                             index: index,
                             onUIViewCreated: onUIViewCreated)
            }
        }
    }
}

public class CustomHostingController: UIHostingController<ContainerView> {
    public var containerViewModel: ContainerViewModel
    private var buttonUIViews: [Int: UIView] = [:]

    public init(containerViewModel: ContainerViewModel) {
        self.containerViewModel = containerViewModel
        super.init(rootView: ContainerView(viewModel: containerViewModel, onUIViewCreated: { [weak self] index, uiView in
            self?.buttonUIViews[index] = uiView
        }))
    }

    @objc required dynamic init?(coder aDecoder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }

    public func getButtonAtIndex(index: Int) -> UIView? {
        return buttonUIViews[index]
    }
}

并按如下方式使用:

let hostingController = CustomHostingController(containerViewModel: yourViewModel)
if let buttonView = hostingController.getButtonAtIndex(index: 2) {
    let popover = ThirdPartyPopoverController(description: "Test", fromSourceView: buttonView)
    // Present your popover
}
© www.soinside.com 2019 - 2024. All rights reserved.