我正在尝试让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))
}
}
编辑:
经过进一步检查,似乎我得到了Unable to simultaneously satisfy constraints.
约束,其中之一是对扩展尺寸的'UIView-Encapsulated-Layout-Height'
约束。因此,我认为这可能有助于防止将这些约束强加于我的观点?不确定...
答案 0 :(得分:3)
使用.fixedSize()
为我解决了这个问题。
我所做的工作使用了UIViewController
,所以UIView
的情况可能有所不同。我试图实现的是做一个三明治结构,如:
SwiftUI => UIKit => SwiftUI
考虑一个简单的SwiftUI视图:
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))
}
}
设置背景色以测试外部SwiftUI的环境值是否传递给内部SwiftUI。普遍的答案是肯定的,但是如果您使用.popover
之类的东西,则需要谨慎。
关于UIHostingController的一件好事是,您可以使用.intrinsicContentSize
获得SwiftUI的自然大小。这适用于诸如Text
和Image
之类的紧密视图,或包含此类紧密视图的容器。但是,我不确定GeometryReader
会发生什么。
考虑以下视图控制器:
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
}
}
这里没有什么特别有趣的。我们为{strong> BOOT 和UIView
托管的SwiftUI关闭了自动调整大小的掩码。我们强迫我们的视图具有与SwiftUI相同的自然尺寸。
我将在稍后讨论更新UIView
。
无聊的preferredContentSize
:
VCRep
现在进入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
}
神奇的是,一切正常。您可以更改水平对齐方式或向视图控制器添加更多字符,并期望使用正确的布局。
注意事项
struct ContentView: View {
@State var alignmentIndex = 0
@State var additionalCharacterCount = 0
var alignment: HorizontalAlignment {
[HorizontalAlignment.leading, HorizontalAlignment.center, HorizontalAlignment.trailing][alignmentIndex % 3]
}
var additionalCharacters: String {
Array(repeating: "x", count: additionalCharacterCount).joined(separator: "")
}
var body: some View {
VStack(alignment: alignment, spacing: 0) {
Button {
self.alignmentIndex += 1
} label: {
Text("Change Alignment")
}
Button {
self.additionalCharacterCount += 1
} label: {
Text("Add characters")
}
Block()
Block().environment(\.colorScheme, .dark)
VCRep(text: additionalCharacters)
.fixedSize()
.environment(\.colorScheme, .dark)
}
}
}
才能使用自然大小。否则,视图控制器将占用尽可能多的空间,就像GeometryReader()一样。鉴于.fixedSize()
的文档,这可能不足为奇,但是命名太可怕了。我从没想到.fixedSize()
会这样。.fixedSize()
并保持更新。最初,我发现它对我的代码没有视觉影响,但是水平对齐似乎是错误的,因为preferredContentSize
始终将其前导锚用作VCRep
的布局指南。通过VStack
检查视图尺寸后,结果发现.alignmentGuide
的尺寸为零。它仍然显示!由于默认情况下未启用任何内容剪切!顺便说一句,如果您遇到的情况是视图高度取决于其宽度,并且您很幸运能够获得宽度(通过VCRep
),则也可以尝试在您的页面上进行布局直接在SwiftUI视图的GeometryReader
中拥有,并将UIView附加为body
以用作自定义绘画工具。例如,如果您使用TextKit计算文本布局,则此方法有效。
答案 1 :(得分:1)
请尝试以下代码,它将为您提供帮助
// **** 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
}
}
示例更改
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)
}
}