我试图让 SwiftUI 识别 UIViewRepresentable 的内在大小,但它似乎把它当作框架设置为maxWidth: .infinity, maxHeight: .infinity. 我创建了一个人为的例子,这是我的代码:
struct Example: View {
var body: some View {
VStack {
Text("Hello")
TestView()
}
.background(Color.red)
}
}
struct TestView: UIViewRepresentable {
func makeUIView(context: UIViewRepresentableContext<TestView>) -> TestUIView {
return TestUIView()
}
func updateUIView(_ uiView: TestUIView, context: UIViewRepresentableContext<TestView>) {
}
typealias UIViewType = TestUIView
}
class TestUIView: UIView {
required init?(coder: NSCoder) { fatalError("-") }
init() {
super.init(frame: .zero)
let label = UILabel()
label.text = "Sed mattis urna a ipsum fermentum, non rutrum lacus finibus. Mauris vel augue lorem. Donec malesuada non est nec fermentum. Integer at interdum nibh. Nunc nec arcu mauris. Suspendisse efficitur iaculis erat, ultrices auctor magna."
label.numberOfLines = 0
label.translatesAutoresizingMaskIntoConstraints = false
label.backgroundColor = .purple
addSubview(label)
translatesAutoresizingMaskIntoConstraints = false
NSLayoutConstraint.activate([
widthAnchor.constraint(equalToConstant: 200),
label.leadingAnchor.constraint(equalTo: leadingAnchor),
label.trailingAnchor.constraint(equalTo: trailingAnchor),
label.topAnchor.constraint(equalTo: topAnchor),
label.bottomAnchor.constraint(equalTo: bottomAnchor),
])
}
}
struct Example_Previews: PreviewProvider {
static var previews: some View {
Example()
.previewDevice(PreviewDevice(rawValue: "iPhone 8"))
.previewLayout(PreviewLayout.fixed(width: 300, height: 300))
}
}
Run Code Online (Sandbox Code Playgroud)
编辑:经过进一步检查,似乎我得到Unable to simultaneously satisfy constraints.了约束之一是'UIView-Encapsulated-Layout-Height'对拉伸尺寸的约束。所以我想这可能有助于防止这些限制强加于我的观点?没有把握...
使用.fixedSize()为我解决了问题。
我所做的使用UIViewController,所以事情可能会有所不同UIView。我试图实现的是做一个三明治结构,如:
SwiftUI => UIKit => SwiftUI
Run Code Online (Sandbox Code Playgroud)
考虑一个简单的 SwiftUI 视图:
SwiftUI => UIKit => SwiftUI
Run Code Online (Sandbox Code Playgroud)
设置背景色是为了测试外部 SwiftUI 的环境值是否传递给内部 SwiftUI。一般的答案是肯定的,但如果您使用诸如.popover.
UIHostingController 的一个好处是您可以使用.intrinsicContentSize. 这适用于诸如Textand 之Image类的紧密视图,或包含此类紧密视图的容器。但是,我不确定GeometryReader.
考虑以下视图控制器:
struct Block: View {
var text: String
init(_ text: String = "1, 2, 3") {
self.text = text
}
var body: some View {
Text(text)
.padding()
.background(Color(UIColor.systemBackground))
}
}
Run Code Online (Sandbox Code Playgroud)
这里没有什么特别有趣的。我们关掉自动调整为面具BOTH我们UIView和SwiftUI的托管服务UIView。我们强制我们的视图具有与 SwiftUI 相同的自然大小。
preferredContentSize稍后我会说更新。
一个无聊VCRep:
class VC: UIViewController {
let hostingController = UIHostingController(rootView: Block("Inside VC"))
var text: String = "" {
didSet {
hostingController.rootView = Block("Inside VC: \(text).")
}
}
override func viewDidLoad() {
addChild(hostingController)
view.addSubview(hostingController.view)
view.topAnchor.constraint(equalTo: hostingController.view.topAnchor).isActive = true
view.bottomAnchor.constraint(equalTo: hostingController.view.bottomAnchor).isActive = true
view.leadingAnchor.constraint(equalTo: hostingController.view.leadingAnchor).isActive = true
view.trailingAnchor.constraint(equalTo: hostingController.view.trailingAnchor).isActive = true
view.translatesAutoresizingMaskIntoConstraints = false
hostingController.view.translatesAutoresizingMaskIntoConstraints = false
}
override func viewDidLayoutSubviews() {
preferredContentSize = view.bounds.size
}
}
Run Code Online (Sandbox Code Playgroud)
现在来到 ContentView,即外部 SwiftUI:
struct VCRep: UIViewControllerRepresentable {
var text: String
func makeUIViewController(context: Context) -> VC {
VC()
}
func updateUIViewController(_ vc: VC, context: Context) {
vc.text = text
}
typealias UIViewControllerType = VC
}
Run Code Online (Sandbox Code Playgroud)
神奇的是,一切正常。您可以更改水平对齐方式或向视图控制器添加更多字符,并期望正确的布局。
需要注意的一点:
.fixedSize()使用自然尺寸。否则视图控制器会占用尽可能多的空间,就像 GeometryReader() 一样。鉴于.fixedSize()的文档,这可能不足为奇,但命名很糟糕。我永远不会期望.fixedSize()这个意思。preferredContentSize并保持更新。最初我发现它对我的代码没有视觉影响,但水平对齐似乎是错误的,因为VCRep总是将其前导锚用作VStack. 通过检查视图尺寸后.alignmentGuide,结果显示VCRep尺寸为零。它仍然显示!由于默认情况下不启用内容剪辑!顺便说一句,如果您遇到视图高度取决于其宽度的情况,并且您很幸运能够获得宽度(通过GeometryReader),您也可以尝试直接在 SwiftUI 视图中自己进行布局body,以及附加你的 UIView 作为.background一个自定义画家。例如,如果您使用 TextKit 来计算您的文本布局,这将起作用。
请尝试下面的代码,它会对您有所帮助
// **** For getting label height ****
struct LabelInfo {
func heightForLabel(text: String, font: UIFont, width: CGFloat) -> CGFloat {
let label:UILabel = UILabel(frame: CGRect(x: 0, y: 0, width: width, height: CGFloat.greatestFiniteMagnitude))
label.numberOfLines = 0
label.lineBreakMode = NSLineBreakMode.byWordWrapping
label.font = font
label.text = text
label.sizeToFit()
return label.frame.height
}
}
Run Code Online (Sandbox Code Playgroud)
示例的变化
struct Example: View {
// Note : Width is fixed 200 at both place
// : use same font at both
let height = LabelInfo().heightForLabel(text: "Sed mattis urna a ipsum fermentum, non rutrum lacus finibus. Mauris vel augue lorem. Donec malesuada non est nec fermentum. Integer at interdum nibh. Nunc nec arcu mauris. Suspendisse efficitur iaculis erat, ultrices auctor magna.", font: UIFont.systemFont(ofSize: 17), width: 200)
var body: some View {
VStack {
Text("Hello")
TestView().frame(width: 200, height: height, alignment: .center) //You need to do change here
}
.background(Color.red)
}
}
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
4768 次 |
| 最近记录: |