Автоматически регулируемая высота просмотра в зависимости от высоты текста в SwiftUI - PullRequest
2 голосов
/ 18 июня 2020

Я пытаюсь создать представление в SwiftUI, в котором фон изображения слева должен масштабироваться по вертикали в зависимости от высоты текста справа.

Я пробовал много разных подходов, начиная с GeometryReader на .layoutPriority(), но мне не удалось заставить ни один из них работать.

Текущее состояние:

Current state

Желаемое состояние:

enter image description here

Я знаю, что могу имитировать функциональность, жестко запрограммировав .frame(100) для примера, который я опубликовал, но поскольку текст справа - это динамика c, это не сработает.

Это полный код для представления на скриншоте:

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 Ответ

2 голосов
/ 18 июня 2020

Вот решение, основанное на ключе предпочтений просмотра. Протестировано с Xcode 11.4 / iOS 13.4

demo

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()
    }
}

...