在 SwiftUI 中根据文本高度自动调整视图高度

Posted

技术标签:

【中文标题】在 SwiftUI 中根据文本高度自动调整视图高度【英文标题】:Automatically adjustable view height based on text height in SwiftUI 【发布时间】:2020-06-18 13:22:13 【问题描述】:

我正在尝试在 SwiftUI 中创建一个视图,其中左侧图像的背景应根据右侧文本的高度垂直缩放。

我尝试了很多不同的方法,从 GeometryReader.layoutPriority(),但我没有设法让它们中的任何一个起作用。

当前状态:

所需状态:

对于我发布的示例,我知道我可以通过对 .frame(100) 进行硬编码来模仿该功能,但由于右侧的文本是动态的,因此这是行不通的。

这是截图中视图的完整代码:

import SwiftUI

struct DynamicallyScalingView: View 
    var body: some View 
        HStack(spacing: 20) 
            Image(systemName: "snow")
                .font(.system(size: 32))
                .padding(20)
                .background(Color.red.opacity(0.4))
                .cornerRadius(8)

            VStack(alignment: .leading, spacing: 8) 
                Text("My Title")
                    .foregroundColor(.white)
                    .font(.system(size: 13))
                    .padding(5)
                    .background(Color.black)
                    .cornerRadius(8)
                Text("Dynamic text that can be of different leghts. Spanning from one to multiple lines. When it's multiple lines, the background on the left should scale vertically")
                    .font(.system(size: 13))
            
        
        .padding(.horizontal)
    


struct DailyFactView_Previews: PreviewProvider 
    static var previews: some View 
        DynamicallyScalingView()
    

【问题讨论】:

【参考方案1】:

这是一个基于视图偏好键的解决方案。使用 Xcode 11.4 / ios 13.4 测试

struct DynamicallyScalingView: View 
    @State private var labelHeight = CGFloat.zero     // << here !!

    var body: some View 
        HStack(spacing: 20) 
            Image(systemName: "snow")
                .font(.system(size: 32))
                .padding(20)
                .frame(minHeight: labelHeight)       // << here !!
                .background(Color.red.opacity(0.4))
                .cornerRadius(8)

            VStack(alignment: .leading, spacing: 8) 
                Text("My Title")
                    .foregroundColor(.white)
                    .font(.system(size: 13))
                    .padding(5)
                    .background(Color.black)
                    .cornerRadius(8)
                Text("Dynamic text that can be of different leghts. Spanning from one to multiple lines. When it's multiple lines, the background on the left should scale vertically")
                    .font(.system(size: 13))
            
            .background(GeometryReader       // << set right side height
                Color.clear.preference(key: ViewHeightKey.self, 
                    value: $0.frame(in: .local).size.height) 
            )
        
        .onPreferenceChange(ViewHeightKey.self)  // << read right side height
            self.labelHeight = $0        // << here !!
        
        .padding(.horizontal)
    


struct ViewHeightKey: PreferenceKey 
    static var defaultValue: CGFloat  0 
    static func reduce(value: inout Value, nextValue: () -> Value) 
        value = value + nextValue()
    


【讨论】:

设置.frame(minHeight: labelHeight)而不是.frame(height: labelHeight)的原因是什么?

以上是关于在 SwiftUI 中根据文本高度自动调整视图高度的主要内容,如果未能解决你的问题,请参考以下文章

如何使用自动布局根据子视图调整父视图的高度

如何在列表视图中为带有自动换行的可变多行长文本自动调整项目高度?

根据最高子视图按钮自动调整超级视图高度

无法根据标签的文本动态调整标签的高度

根据最大的子视图使用自动布局调整超级视图的大小

动态表视图高度