我有一个List
显示当前月份的天数。中的每一行都List
包含缩写的天,a Divider
和a中的天数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()
}
}
}
Run Code Online (Sandbox Code Playgroud)
的实例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)
}
}
}
Run Code Online (Sandbox Code Playgroud)
代码的结果如下:
这可能不是很明显,但是分隔符没有对齐,因为文本的宽度可能在行与行之间变化。我要实现的是使包含日期信息的视图具有相同的宽度,以便它们在视觉上对齐。
我尝试使用GeometryReader
和frame()
修饰符来设置最小宽度,理想宽度和最大宽度,但是我需要确保使用动态类型设置可以使文本缩小和增长。我选择不使用父级百分比的宽度,因为我不确定如何确定本地化文本始终适合允许的宽度。
如何修改我的视图,以使行中的每个视图具有相同的宽度,而不管文本的宽度如何?
关于动态类型,我将创建一个更改该设置时要使用的不同布局。
我使用GeometryReader
和来工作Preferences
。
首先,在ContentView
中添加此属性:
@State var maxLabelWidth: CGFloat = 0
Run Code Online (Sandbox Code Playgroud)
然后,在DayListItem
中添加此属性:
@Binding var maxLabelWidth: CGFloat
Run Code Online (Sandbox Code Playgroud)
接下来,在中ContentView
,传递self.$maxLabelWidth
到的每个实例DayListItem
:
List(currentMonth.days.identified(by: \.self)) { date in
DayListItem(date: date, maxLabelWidth: self.$maxLabelWidth)
}
Run Code Online (Sandbox Code Playgroud)
现在,创建一个名为的结构WidthPreferenceKey
:
struct WidthPreferenceKey: PreferenceKey {
typealias Value = CGFloat
static var defaultValue: CGFloat = 0
static func reduce(value: inout CGFloat, nextValue: () -> CGFloat) {
value = nextValue()
}
}
Run Code Online (Sandbox Code Playgroud)
这符合PreferenceKey
协议,允许您在视图之间传递首选项时将此结构用作键。
接下来,创建一个View
被调用的DayListItemGeometry
-这将用于确定VStack
in 的宽度DayListItem
:
struct DayListItemGeometry: View {
var body: some View {
GeometryReader { geometry in
Rectangle()
.fill(Color.clear)
.preference(key: WidthPreferenceKey.self, value: geometry.size.width)
}
.scaledToFill()
}
}
Run Code Online (Sandbox Code Playgroud)
然后,在中DayListItem
,将代码更改为此:
HStack {
VStack(alignment: .center) {
Text(weekdayFormatter.string(from: date))
.font(.caption)
.foregroundColor(.secondary)
Text(dayNumberFormatter.string(from: date))
.font(.body)
.foregroundColor(.red)
}
.frame(width: self.maxLabelWidth)
.background(DayListItemGeometry())
.onPreferenceChange(WidthPreferenceKey.self) {
if $0 > self.maxLabelWidth {
self.maxLabelWidth = $0
}
}
Divider()
}
Run Code Online (Sandbox Code Playgroud)
我完成的工作是创建一个GeometryReader
可缩放的,以填充的背景,该背景VStack
本身根据文本的大小进行调整。然后,我将其宽度设置GeometryReader
为首选项,然后阅读该首选项更改并maxLabelWidth
在必要时进行更新。然后,我将的框架设置VStack
为.frame(width: self.maxLabelWidth)
,并且由于maxLabelWidth
是绑定的,因此每当计算DayListItem
新的框架时都会对其进行更新maxLabelWidth
。
归档时间: |
|
查看次数: |
930 次 |
最近记录: |