gpt4 book ai didi

swiftui - 在列表行中制作等宽的 SwiftUI View

转载 作者:行者123 更新时间:2023-12-04 13:30:24 27 4
gpt4 key购买 nike

我有一个 List显示当月的天数。 List 中的每一行包含缩写的日期,a Divider ,以及 VStack 中的天数. VStack然后嵌入到 HStack这样我就可以在日期和数字的右侧有更多的文字。

struct DayListItem : View {

// MARK: - Properties

let date: Date

private let weekdayFormatter: DateFormatter = {
let formatter = DateFormatter()
formatter.dateFormat = "EEE"
return formatter
}()

private let dayNumberFormatter: DateFormatter = {
let formatter = DateFormatter()
formatter.dateFormat = "d"
return formatter
}()

var body: some View {
HStack {
VStack(alignment: .center) {
Text(weekdayFormatter.string(from: date))
.font(.caption)
.foregroundColor(.secondary)
Text(dayNumberFormatter.string(from: date))
.font(.body)
.foregroundColor(.red)
}
Divider()
}
}

}
DayListItem 的实例用于 ContentView :

struct ContentView : View {

// MARK: - Properties

private let dataProvider = CalendricalDataProvider()

private var navigationBarTitle: String {
let formatter = DateFormatter()
formatter.dateFormat = "MMMM YYY"
return formatter.string(from: Date())
}

private var currentMonth: Month {
dataProvider.currentMonth
}

private var months: [Month] {
return dataProvider.monthsInRelativeYear
}

var body: some View {
NavigationView {
List(currentMonth.days.identified(by: \.self)) { date in
DayListItem(date: date)
}
.navigationBarTitle(Text(navigationBarTitle))
.listStyle(.grouped)
}
}

}

代码结果如下:

Screenshot of app running in Xcode Simulator

这可能不是很明显,但是分隔线没有对齐,因为文本的宽度可能因行而异。我想要实现的是让包含日期信息的 View 具有相同的宽度,以便它们在视觉上对齐。

我试过使用 GeometryReaderframe()修饰符来设置最小宽度、理想宽度和最大宽度,但我需要确保文本可以通过动态类型设置收缩和增长;我选择不使用占父级百分比的宽度,因为我不确定如何确保本地化文本始终适合允许的宽度。

如何修改我的 View ,使行中的每个 View 都具有相同的宽度,而不管文本的宽度如何?

关于动态类型,我将创建一个不同的布局以在更改该设置时使用。

最佳答案

我使用 GeometryReader 让它工作和 Preferences .
首先,在 ContentView ,添加此属性:

@State var maxLabelWidth: CGFloat = .zero
然后,在 DayListItem ,添加此属性:
@Binding var maxLabelWidth: CGFloat
接下来,在 ContentView ,通过 self.$maxLabelWidthDayListItem 的每个实例:
List(currentMonth.days.identified(by: \.self)) { date in
DayListItem(date: date, maxLabelWidth: self.$maxLabelWidth)
}
现在,创建一个名为 MaxWidthPreferenceKey 的结构。 :
struct MaxWidthPreferenceKey: PreferenceKey {
static var defaultValue: CGFloat = .zero

static func reduce(value: inout CGFloat, nextValue: () -> CGFloat) {
let nextValue = nextValue()

guard nextValue > value else { return }

value = nextValue
}
}
这符合 PreferenceKey协议(protocol),允许您在 View 之间传达偏好时使用此结构作为键。
接下来,创建一个 View调用 DayListItemGeometry - 这将用于确定 VStack 的宽度在 DayListItem :
struct DayListItemGeometry: View {
var body: some View {
GeometryReader { geometry in
Color.clear
.preference(key: MaxWidthPreferenceKey.self, value: geometry.size.width)
}
.scaledToFill()
}
}
然后,在 DayListItem ,将您的代码更改为:
HStack {
VStack(alignment: .center) {
Text(weekdayFormatter.string(from: date))
.font(.caption)
.foregroundColor(.secondary)
Text(dayNumberFormatter.string(from: date))
.font(.body)
.foregroundColor(.red)
}
.background(DayListItemGeometry())
.onPreferenceChange(MaxWidthPreferenceKey.self) {
self.maxLabelWidth = $0
}
.frame(width: self.maxLabelWidth)

Divider()
}
我所做的是我创建了一个 GeometryReader并将其应用于 VStack 的背景.几何告诉我 VStack 的尺寸根据文本大小自行调整大小。 MaxWidthPreferenceKey每当几何发生变化时更新,在 reduce 之后内部函数 MaxWidthPreferenceKey计算最大宽度,我阅读了偏好更改并更新 self.maxLabelWidth .然后我设置 VStack 的框架成为 .frame(width: self.maxLabelWidth) ,并且由于 maxLabelWidth具有约束力,每 DayListItem当新的 maxLabelWidth 更新时是计算出来的。请记住,这里的顺序很重要。放置 .frame .background 之前的修饰符和 .onPreferenceChange不管用。
Canvas Screenshot

关于swiftui - 在列表行中制作等宽的 SwiftUI View ,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/56997725/

27 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com