我正在尝试使用在 SwiftUI 中使用 UIKit 创建的组件UIViewRepresentable. The result I want to achieve is to have a textfield on top of my view and my UIKit view stacked at the bottom with an automatic height.
问题是这个组件包含一个多行标签,据我所知,它使得自动高度很难正常工作,所以我的 UIKit 组件占用了 VStack 中的所有可用空间。
这是我的代码,包含在游乐场中以对其进行测试。我尝试着拥抱优先级,但没有任何效果对我来说,如果我使用快速 UI 视图进行测试,它可以正常工作..有什么想法吗?
import UIKit
import Foundation
import SwiftUI
import PlaygroundSupport
class InformationView: UIView {
lazy var label = UILabel()
lazy var button = UIButton(type: .custom)
override init(frame: CGRect) {
super.init(frame: frame)
backgroundColor = .red
addSubview(label)
addSubview(button)
label.text = "zaeiof azoeinf aozienf oaizenf oazeinf oaziefj oazeijf oaziejf aozijf oaizje foazeafjoj"
label.numberOfLines = 0
label.setContentHuggingPriority(.required, for: .vertical)
label.translatesAutoresizingMaskIntoConstraints = false
button.translatesAutoresizingMaskIntoConstraints = false
button.setTitle("My button title", for: .normal)
button.setContentCompressionResistancePriority(.required, for: .horizontal)
addConstraints([
label.leadingAnchor.constraint(equalTo: leadingAnchor),
label.topAnchor.constraint(equalTo: topAnchor),
label.bottomAnchor.constraint(equalTo: bottomAnchor),
label.trailingAnchor.constraint(equalTo: button.leadingAnchor, constant: -10),
button.trailingAnchor.constraint(equalTo: trailingAnchor),
button.centerYAnchor.constraint(equalTo: centerYAnchor)
])
}
required init?(coder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
}
struct InformationRepresenter: UIViewRepresentable {
func makeUIView(context: Context) -> InformationView {
let view = InformationView(frame: .zero)
view.setContentHuggingPriority(.required, for: .vertical)
return view
}
func updateUIView(_ uiView: InformationView, context: Context) {
}
}
struct Info: View {
var body: some View {
return HStack {
Text("zaeiof azoeinf aozienf oaizenf oazeinf oaziefj oazeijf oaziejf aozijf oaizje foazeafjoj")
Button("My button title", action: {
print("test")
})
}
}
}
struct ContentView: View {
@State var text = ""
var body: some View {
VStack {
TextField("Field", text: $text)
.padding()
Spacer()
// SwiftUI works
// Info().background(Color.red).padding()
// UIViewRepresentable doesn't
InformationRepresenter().padding()
}
}
}
PlaygroundPage.current.setLiveView(ContentView().frame(width: 400, height: 800, alignment: .top))
Run Code Online (Sandbox Code Playgroud)
Mat*_*omi 10
这里发生了一些事情。
InformationView没有intrinsicContentSize. SwiftUI 依赖此属性来确定 aUIView的理想大小。fixedSize修饰符。此修饰符强制视图保持其理想大小,而不是增长以填充其父级。您无法添加 an intrinsicContentSize,因为内容大小是动态的;它基于标签中的行数。
您无法添加fixedSize修饰符,因为如果没有intrinsicContentSize,这会将大小设置为 (0,0)。
一种解决方案是包装InformationView一个UIView测量尺寸的InformationView变量,并intrinsicContentSize根据该测量值更新它自己的尺寸。
你InformationView应该填满屏幕的宽度;它没有固有宽度。另一方面,固有高度应等于压缩后的系统布局尺寸的高度。这是“基于其约束的视图的最佳大小”。
这是包装器:
class IntrinsicHeightView<ContentView: UIView>: UIView {
var contentView: ContentView
init(contentView: ContentView) {
self.contentView = contentView
super.init(frame: .zero)
backgroundColor = .clear
addSubview(contentView)
}
@available(*, unavailable) required init?(coder _: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
private var contentHeight: CGFloat = .zero {
didSet { invalidateIntrinsicContentSize() }
}
override var intrinsicContentSize: CGSize {
.init(width: UIView.noIntrinsicMetric, height: contentHeight)
}
override var frame: CGRect {
didSet {
guard frame != oldValue else { return }
contentView.frame = self.bounds
contentView.layoutIfNeeded()
let targetSize = CGSize(width: frame.width, height: UIView.layoutFittingCompressedSize.height)
contentHeight = contentView.systemLayoutSizeFitting(
targetSize,
withHorizontalFittingPriority: .required,
verticalFittingPriority: .fittingSizeLevel).height
}
}
}
Run Code Online (Sandbox Code Playgroud)
这IntrinsicHeightView是一个通用的,当其框架发生变化时,根据其内容视图的压缩系统布局高度UIView重新计算其高度。intrinsicContentSize
以下是更新InformationRepresenter:
struct InformationRepresenter: UIViewRepresentable {
func makeUIView(context: Context) -> IntrinsicHeightView<InformationView> {
return IntrinsicHeightView(contentView: InformationView())
}
func updateUIView(_ uiView: IntrinsicHeightView<InformationView>, context: Context) {
}
}
Run Code Online (Sandbox Code Playgroud)
最后,在 SwiftUI 中使用它时:
InformationRepresenter()
.padding()
.fixedSize(horizontal: false, vertical: true)
Run Code Online (Sandbox Code Playgroud)
fixedSize以这种方式使用修改器可以UIView填充父级,但用作intrinsicContentSize.height其高度。这是 最终结果。祝你好运!
| 归档时间: |
|
| 查看次数: |
1996 次 |
| 最近记录: |