我有一个自定义 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];`
您需要将 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
}