简体   繁体   English

如何一致地分离 HStack 上的元素

[英]How to consistently separate elements on a HStack

I have a set of elements on a HStack that are composed of a circle and some label text underneath it.我在HStack上有一组元素,它们由一个圆圈和一些 label 文本组成。 These elements have a separation between them.这些元素之间有一个分隔。

元素的图片

Everything works as expected until one of the labels is bigger than the circle.一切都按预期工作,直到其中一个标签大于圆圈。 Then, the text increases the actual width of the element, making the visible separation between the circles, off.然后,文本增加了元素的实际宽度,使圆圈之间的可见分离关闭。

在此处输入图像描述

Is there any way to evenly separate the circles, ignoring the text?有什么方法可以均匀地分开圆圈,忽略文字?

struct Item: View {
    let color: Color
    let label: String
    
    var body: some View {
        VStack {
            Circle()
                .fill(color)
                .frame(width: 40, height: 40)
            Text(label)
        }
    }
}

struct ItemSeparation: View {
    var body: some View {
        HStack(alignment: .top, spacing: 30) {
            Item(color: .yellow, label: "Berlin")
            Item(color: .green, label: "Copenhagen")
            Item(color: .blue, label: "Madrid")
            Item(color: .purple, label: "Helsinki")
        }
    }
}

These two solutions have different compromises.这两种解决方案有不同的折衷方案。 You'll need to decide what happens, for example, if the views will be too wide for the parent view based on the longest label.您需要决定会发生什么,例如,如果视图对于基于最长 label 的父视图来说太宽。 Option 1 wraps the text.选项 1 换行文本。 Option 2 makes the view expand beyond its parent.选项 2 使视图扩展到其父级之外。

Option #1:选项1:

Use LazyVGrid :使用LazyVGrid

struct ContentView: View {
    let columns = [
            GridItem(.flexible()),
            GridItem(.flexible()),
            GridItem(.flexible()),
            GridItem(.flexible()),
        ]

    
    var body: some View {
        LazyVGrid(columns: columns, spacing: 30) {
            Item(color: .yellow, label: "Berlin")
            Item(color: .green, label: "Copenhagen")
            Item(color: .blue, label: "Madrid")
            Item(color: .purple, label: "Helsinki")
        }
    }
}

Option #2:选项#2:

Use a PreferenceKey and a GeometryReader to get the size of the widest View and propagate the changes back up to the parent.使用PreferenceKeyGeometryReader获取最宽View的大小并将更改传播回父级。

struct Item: View {
    let color: Color
    let label: String
    let width: CGFloat
    
    var body: some View {
        VStack {
            Circle()
                .fill(color)
                .frame(width: 40, height: 40)
            Text(label)
        }
        .border(Color.blue)
        .background(
            GeometryReader {
                Color.clear.preference(key: ViewWidthKey.self,
                                   value: $0.size.width)
            }.scaledToFill()
        )
        .frame(width: width)
    }
}

struct ViewWidthKey: PreferenceKey {
    static var defaultValue: CGFloat { 0 }
    static func reduce(value: inout Value, nextValue: () -> Value) {
        let nextValue = nextValue()
        guard nextValue > value else { return }
        value = nextValue
    }
}

struct ContentView: View {
    @State private var maxWidth : CGFloat = 0
    
    var body: some View {
        HStack(alignment: .top, spacing: 30) {
            Item(color: .yellow, label: "Berlin", width: maxWidth)
            Item(color: .green, label: "Copenhagen", width: maxWidth)
            Item(color: .blue, label: "Madrid", width: maxWidth)
            Item(color: .purple, label: "Helsinki", width: maxWidth)
        }.onPreferenceChange(ViewWidthKey.self) { width in
            self.maxWidth = width
            print(width)
        }
    }
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM