首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >UIViewControllerRepresentable未正确占用空间

UIViewControllerRepresentable未正确占用空间
EN

Stack Overflow用户
提问于 2021-04-24 01:30:10
回答 2查看 495关注 0票数 1

我正在尝试在SwiftUI视图中使用自定义UIViewController。我设置了一个UIViewControllerRepresentable类,它在makeUIViewController方法中创建UIViewController。这将创建UIViewController并显示按钮,但是,UIViewControllerRepresentable不会占用任何空间。

我尝试使用UIImagePickerController而不是我的自定义控制器,并且大小正确。让我的控制器占用空间的唯一方法是在我的SwiftUI视图中的UIViewControllerRepresentable上设置一个固定的框架,这是我绝对不想做的。

注意:我确实需要使用UIViewController,因为我正在尝试在SwiftUI中实现UIMenuController。我得到了所有的工作,除了这个问题,我有与它不正确的大小。

下面是我的代码:

代码语言:javascript
复制
struct ViewControllerRepresentable: UIViewControllerRepresentable {
    func makeUIViewController(context: Context) -> MenuViewController {
        let controller = MenuViewController()
        return controller
    }
    
    func updateUIViewController(_ uiViewController: MenuViewController, context: Context) {
        
    }
}

class MenuViewController: UIViewController {
    override func viewDidLoad() {
        let button = UIButton()
        button.setTitle("Test button", for: .normal)
        button.setTitleColor(.red, for: .normal)
        
        self.view.addSubview(button)
        button.translatesAutoresizingMaskIntoConstraints = false
        button.leadingAnchor.constraint(equalTo: self.view.leadingAnchor).isActive = true
        button.trailingAnchor.constraint(equalTo: self.view.trailingAnchor).isActive = true
        button.topAnchor.constraint(equalTo: self.view.topAnchor).isActive = true
        button.bottomAnchor.constraint(equalTo: self.view.bottomAnchor).isActive = true
    }
}

我的SwiftUI视图:

代码语言:javascript
复制
struct ClientView: View {
    var body: some View {
        VStack(spacing: 0) {
            EntityViewItem(copyValue: "copy value", label: {
                Text("Name")
            }, content: {
                Text("Random name")
            })
            .border(Color.green)
            
            ViewControllerRepresentable()
                .border(Color.red)
            
            EntityViewItem(copyValue: "copy value", label: {
                Text("Route")
            }, content: {
                HStack(alignment: .center) {
                    Text("Random route name")
                }
            })
            .border(Color.blue)
        }
    }
}

截图:

我没有太多使用UIKit的经验--我唯一的经验是编写在SwiftUI中使用的UIKit视图。这个问题很可能与我缺乏UIKit知识有关。

提前感谢!

编辑:

以下是EntityViewItem的代码。我还将提供ClientViewEntityView中的容器视图。

我还清理了其余代码,并用硬编码的值替换了对Entity的引用。

代码语言:javascript
复制
struct EntityViewItem<Label: View, Content: View>: View {
    var copyValue: String
    var label: Label
    var content: Content
    var action: (() -> Void)?
    
    init(copyValue: String, @ViewBuilder label: () -> Label, @ViewBuilder content: () -> Content, action: (() -> Void)? = nil) {
        self.copyValue = copyValue
        self.label = label()
        self.content = content()
        self.action = action
    }
    
    var body: some View {
        VStack(alignment: .leading, spacing: 2) {
            label
                .opacity(0.6)
            content
                .onTapGesture {
                    guard let unwrappedAction = action else {
                        return
                    }
                    unwrappedAction()
                }
                .contextMenu {
                    Button(action: {
                        UIPasteboard.general.string = copyValue
                    }) {
                        Text("Copy to clipboard")
                        Image(systemName: "doc.on.doc")
                    }
                }
        }
        .padding([.top, .leading, .trailing])
        .frame(maxWidth: .infinity, alignment: .leading)
    }
}

ClientView的容器

代码语言:javascript
复制
struct EntityView: View {
    let headerHeight: CGFloat = 56
    
    var body: some View {
        ZStack {
            ScrollView(showsIndicators: false) {
                VStack(spacing: 0) {
                    Color.clear.frame(
                        height: headerHeight
                    )
                    ClientView()
                }
            }
            VStack(spacing: 0) {
                HStack {
                    Button(action: {
                    }, label: {
                        Text("Back")
                    })
                    Spacer()
                    Text("An entity name")
                        .lineLimit(1)
                        .minimumScaleFactor(0.5)
                    
                    Spacer()
                    Color.clear
                        .frame(width: 24, height: 0)
                }
                .frame(height: headerHeight)
                .padding(.leading)
                .padding(.trailing)
                .background(
                    Color.white
                        .ignoresSafeArea()
                        .opacity(0.95)
                )
                Spacer()
            }
        }
    }
}
EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2021-04-25 01:46:17

非常感谢@udbhateja和@jnpdx的帮助。这就解释了为什么UIViewControllerRepresentableScrollView中压缩它的框架。我最终找到了一个解决我的问题的方法,其中包括在UIViewControllerRepresentable上设置一个固定的高度。基本上,我使用PreferenceKey来查找SwiftUI视图的高度,并设置UIViewControllerRepresentable的框架以与之匹配。

如果有人遇到同样的问题,下面是我的代码:

代码语言:javascript
复制
struct EntityViewItem<Label: View, Content: View>: View {
    var copyValue: String
    var label: Label
    var content: Content
    var action: (() -> Void)?
    
    @State var height: CGFloat = 0
    
    init(copyValue: String, @ViewBuilder label: () -> Label, @ViewBuilder content: () -> Content, action: (() -> Void)? = nil) {
        self.copyValue = copyValue
        self.label = label()
        self.content = content()
        self.action = action
    }
    
    var body: some View {
        ViewControllerRepresentable(copyValue: copyValue) {
            SizingView(height: $height) { // This calculates the height of the SwiftUI view and sets the binding
                VStack(alignment: .leading, spacing: 2) {
                    // Content
                }
                .padding([.leading, .trailing])
                .padding(.top, 10)
                .padding(.bottom, 10)
                .frame(maxWidth: .infinity, alignment: .leading)
            }
        }
        .frame(height: height) // Here I set the height to the value returned from the SizingView
    }
}

SizingView的代码

代码语言:javascript
复制
struct SizingView<T: View>: View {
    
    let view: T
    @Binding var height: CGFloat
    
    init(height: Binding<CGFloat>, @ViewBuilder view: () -> T) {
        self.view = view()
        self._height = height
    }
    var body: some View {
        view.background(
            GeometryReader { proxy in
                Color.clear
                    .preference(key: SizePreferenceKey.self, value: proxy.size)
            }
        )
        .onPreferenceChange(SizePreferenceKey.self) { preferences in
            height = preferences.height
        }

    }
    
    func size(with view: T, geometry: GeometryProxy) -> T {
        height = geometry.size.height
        return view
    }
}

struct SizePreferenceKey: PreferenceKey {
    static var defaultValue: CGSize = .zero

    static func reduce(value: inout CGSize, nextValue: () -> CGSize) {
        value = nextValue()
    }
}

完成此操作后,我的UIMenuController就可以完全发挥作用了。它有很多代码(如果这个功能存在于SwiftUI中,我可能不得不写5行代码),但它工作得很好。如果任何人喜欢的代码,请评论,我会分享。

以下是最终产品的图像:

票数 2
EN

Stack Overflow用户

发布于 2021-04-24 15:52:25

正如@jnpdx提到的,你需要通过框架提供显式的大小,以使可表示项可见,因为它嵌套在VStack和其他视图中。

如果您有使用UIViewController的特殊原因,那么一定要提供显式框架,或者创建一个SwiftUI视图。

代码语言:javascript
复制
struct ClientView: View {
  var body: some View {
    VStack(spacing: 0) {
        EntityViewItem(copyValue: "copy value", label: {
            Text("Name")
        }, content: {
            Text("Random name")
        })
        .border(Color.green)
        
        ViewControllerRepresentable()
            .border(Color.red)
            .frame(height: 100.0)
        
        EntityViewItem(copyValue: "copy value", label: {
            Text("Route")
        }, content: {
            HStack(alignment: .center) {
                Text("Random route name")
            }
        })
        .border(Color.blue)
    }
  }
}
票数 2
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/67234508

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档