基于文本高度自动调整视图高度的SwiftUI

7

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

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

当前状态:

Current state

期望状态:

enter image description here

我知道我可以通过设置.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()
    }
}
2个回答

14

这里是一种基于视图偏好键的解决方案。在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) 的原因是什么? - Nace
2
我在至少一篇帖子中看到您在使用首选项键。我真的不明白为什么您要让其他开发者的工作变得更加困难。您在这里所做的将会误导很多初学者,包括我自己。请不要仅仅为了回答而回答。如果您对某些事情不确定,请让问题“腐烂”,我相信有人会找到适当的解决方案,而不需要丑陋的变通方法。您可以在下面检查正确的答案。https://dev59.com/t7voa4cB1Zd3GeqP8rAd#75034970 - Farid

10

这是没有变通方法的答案。

struct DynamicallyScalingView: View {
    var body: some View {
        HStack(spacing: 20) {
            Image(systemName: "snow")
                .frame(maxHeight: .infinity)          // Add this
                .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))
            }
            .frame(maxHeight: .infinity)              // Add this
        }
        .padding(.horizontal)
        .fixedSize(horizontal: false, vertical: true) // Add this
    }
}

enter image description here


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接