Ios 通过UIViewRepresentable like Text在SwiftUI中调整UILabel的大小,以包裹多行

Ios 通过UIViewRepresentable like Text在SwiftUI中调整UILabel的大小,以包裹多行,ios,swiftui,uilabel,uiviewrepresentable,Ios,Swiftui,Uilabel,Uiviewrepresentable,目标是通过uiviewsrepresentable集成UILabel以与Text相同的大小-使用可用的宽度和多行换行以适应所有文本,从而增加HStack的高度,而不是无限扩展宽度。这与非常相似,尽管公认的答案不适用于我使用的涉及滚动视图、VStack和HStack的布局 struct ContentView: View { var body: some View { ScrollView { VStack { HSt

目标是通过
uiviewsrepresentable
集成
UILabel
以与
Text
相同的大小-使用可用的宽度和多行换行以适应所有文本,从而增加
HStack
的高度,而不是无限扩展宽度。这与非常相似,尽管公认的答案不适用于我使用的涉及
滚动视图
VStack
HStack
的布局

struct ContentView: View {
    var body: some View {
        ScrollView {
            VStack {
                HStack {
                    Text("Hello, World")
                    
                    Text("Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nulla tempor justo quam, quis suscipit leo sollicitudin vel.")
                    
                    //LabelView(text: "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nulla tempor justo quam, quis suscipit leo sollicitudin vel.")
                }
                HStack {
                    Text("Hello, World")
                    
                    Text("Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nulla tempor justo quam, quis suscipit leo sollicitudin vel.")
                }
                
                Spacer()
            }
        }
    }
}

struct LabelView: UIViewRepresentable {
    var text: String

    func makeUIView(context: UIViewRepresentableContext<LabelView>) -> UILabel {
        let label = UILabel()
        label.text = text
        label.numberOfLines = 0
        return label
    }

    func updateUIView(_ uiView: UILabel, context: UIViewRepresentableContext<LabelView>) {
        uiView.text = text
    }
}

struct ContentView_Previews: PreviewProvider {
    static var previews: some View {
        ContentView()
    }
}
struct ContentView:View{
var body:一些观点{
滚动视图{
VStack{
HStack{
文本(“你好,世界”)
文本(“Lorem ipsum door sit amet,concetetur adipiscing elite.Nulla tempor justo quam,quis suscipit leo sollicitudin vel.”)
//LabelView(文字:“Lorem ipsum door sit amet,concetetur adipising elite.Nulla tempor justo quam,quis suscipit leo sollicitudin vel.”)
}
HStack{
文本(“你好,世界”)
文本(“Lorem ipsum door sit amet,concetetur adipiscing elite.Nulla tempor justo quam,quis suscipit leo sollicitudin vel.”)
}
垫片()
}
}
}
}
结构LabelView:UIViewRepresentable{
变量文本:字符串
func makeUIView(上下文:UIViewRepresentableContext)->UILabel{
let label=UILabel()
label.text=文本
label.numberOfLines=0
退货标签
}
func updateUIView(uiView:UILabel,context:UIViewRepresentableContext){
uiView.text=文本
}
}
结构内容视图\u预览:PreviewProvider{
静态var预览:一些视图{
ContentView()
}
}
在HStack中使用两个文本可以得到所需的布局:

使用文本和LabelView会产生这种不需要的布局:

如果将
LabelView
包装在
GeometryReader
中,并将
宽度
传递到
LabelView
中以设置
preferredMaxLayoutWidth
,出于某种原因,它是
0.0
。如果将
GeometryReader
移动到
ScrollView
之外,则可以获得一个宽度,但这是滚动视图宽度,而不是SwiftUI为
HStack
中的
LabelView
建议的宽度

struct ContentView: View {
    var body: some View {
        ScrollView {
            VStack {
                HStack {
                    Text("Hello, World")
                    
                    Text("Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nulla tempor justo quam, quis suscipit leo sollicitudin vel.")
                    
                    //LabelView(text: "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nulla tempor justo quam, quis suscipit leo sollicitudin vel.")
                }
                HStack {
                    Text("Hello, World")
                    
                    Text("Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nulla tempor justo quam, quis suscipit leo sollicitudin vel.")
                }
                
                Spacer()
            }
        }
    }
}

struct LabelView: UIViewRepresentable {
    var text: String

    func makeUIView(context: UIViewRepresentableContext<LabelView>) -> UILabel {
        let label = UILabel()
        label.text = text
        label.numberOfLines = 0
        return label
    }

    func updateUIView(_ uiView: UILabel, context: UIViewRepresentableContext<LabelView>) {
        uiView.text = text
    }
}

struct ContentView_Previews: PreviewProvider {
    static var previews: some View {
        ContentView()
    }
}

如果改为指定
label.setContentCompressionResistancePriority(.defaultLow,for:.horizontal)
,效果会更好,但仍然不会显示所有文本,奇怪的是,它将
LabelView
截断为3行,将第二个
文本
截断为2行。

这里的问题在于
滚动视图
需要确定的高度,但representable没有提供它。可能的解决方案是动态计算包装文本高度并显式指定它

注意:由于高度是动态计算的,因此仅在运行时可用,因此无法使用预览进行测试

使用Xcode 12/iOS 14进行测试


这不是一个具体的答案

我意外地发现,固定大小修改器可以帮助将UILabel自动调整为其内容大小

struct ContentView:View{
let attributedString:NSAttributedString
var body:一些观点{
滚动视图{
LazyVStack(间距:10){
RepresentedUILabelView(AttributeText:attributedString)
.框架(最大高度:300)
.fixedSize(水平:假,垂直:真)
.背景(颜色.橙色.不透明度(0.5))
}
.padding()
}
}
}
struct RepresentedUILabelView:UIViewRepresentable{
typealias UIViewType=UILabel
var attributedText:NSAttributedString
func makeUIView(上下文:context)->UILabel{
let label=UILabel()
label.numberOfLines=0
label.lineBreakMode=.byTruncatingTail
label.textAlignment=.justized
label.allowsDefaultThreadingForTruncation=true
//压缩阻力对于启用此视图的自动调整大小非常重要,
//这是基于SwiftUI布局的。
//尤其是当SwiftUI框架修改器应用于此视图时。
label.setContentCompressionResistancePriority(.defaultLow,用于:。水平)
label.setContentCompressionResistancePriority(.defaultLow,用于:。垂直)
//也许这是没有必要的。
label.clipstobunds=true
退货标签
}
func updateUIView(uiView:UILabel,context:context){
打印(#文件ID,#函数)
uiView.attributedText=attributedText
}
}
演示:


此外,如果您不希望提供最大高度。您可以将
preferredMaxLayoutWidth
设置为屏幕宽度。如果你把它放在updateUIView方法中,每当屏幕方向改变时,这个方法也会被调用

func updateUIView(uiView:UILabel,context:context){
uiView.attributedText=attributedText
uiView.preferredMaxLayoutWidth=0.9*UIScreen.main.bounds.width
}


为了完整起见,这是我用来测试视图的属性文本设置。但是,它不应影响视图大小调整的工作方式

func makeAttributedString(fromString s:String)->NSAttributedString{
let content=NSMutableAttributedString(字符串:s)
设paraStyle=NSMutableParagraphStyle()
paraStyle.alignment=.justized
paraStyle.lineHeightMultiple=1.25
paraStyle.lineBreakMode=.ByTruncingTail
paraStyle.hyphentationFactor=1.0
content.addAttribute(.paragraphStyle,