ios - 正确对齐 HStack 中的两个 SwiftUI 文本视图
问题描述
我有一个包含两行的简单列表视图。
每行包含两个文本视图。查看一和查看二。
我想对齐每行中的最后一个标签(查看两个),以便名称标签前导对齐并保持对齐,无论字体大小如何。
第一个标签(查看一个)也需要前导对齐。
我尝试在第一个标签(查看一个)上设置最小帧宽度,但它不起作用。设置最小宽度并让文本视图在视图一中对齐似乎也是不可能的。
有任何想法吗?这在 UIKit 中是相当直接的。
解决方案
我找到了一种解决此问题的方法,该方法支持动态类型并且不是 hacky。答案是使用PreferenceKeys和GeometryReader!
这个解决方案的本质是每个数字Text
都有一个宽度,根据它的文本大小绘制它。GeometryReader
可以检测到这个宽度,然后我们可以将PreferenceKey
其冒泡到 List 本身,其中可以跟踪最大宽度,然后分配给每个 numberText
的帧宽度。
APreferenceKey
是您使用关联类型创建的类型(可以是任何符合 的结构Equatable
,这是您存储有关首选项的数据的位置),它附加到任何View
类型,当它附加时,它会在视图树中冒泡,并且可以是使用 . 在祖先视图中收听.onPreferenceChange(PreferenceKeyType.self)
。
首先,我们将创建 PreferenceKey 类型及其包含的数据:
struct WidthPreferenceKey: PreferenceKey {
typealias Value = [WidthPreference]
static var defaultValue: [WidthPreference] = []
static func reduce(value: inout [WidthPreference], nextValue: () -> [WidthPreference]) {
value.append(contentsOf: nextValue())
}
}
struct WidthPreference: Equatable {
let width: CGFloat
}
接下来,我们将创建一个名为 View 的视图,该视图WidthPreferenceSettingView
将附加到我们想要调整大小的任何背景(在本例中为数字标签)。这将负责设置首选项,该首选项将使用 PreferenceKeys 传递此数字标签的首选宽度。
struct WidthPreferenceSettingView: View {
var body: some View {
GeometryReader { geometry in
Rectangle()
.fill(Color.clear)
.preference(
key: WidthPreferenceKey.self,
value: [WidthPreference(width: geometry.frame(in: CoordinateSpace.global).width)]
)
}
}
}
最后,列表本身!我们有一个@State 变量,它是数字“列”的宽度(从数字不直接影响代码中其他数字的意义上说,这并不是真正的列)。通过.onPreferenceChange(WidthPreference.self)
我们监听我们创建的首选项的变化并将最大宽度存储在我们的宽度状态中。在绘制完所有数字标签并由 GeometryReader 读取它们的宽度后,宽度会向上传播并且最大宽度由.frame(width: width)
struct ContentView: View {
@State private var width: CGFloat? = nil
var body: some View {
List {
HStack {
Text("1. ")
.frame(width: width, alignment: .leading)
.lineLimit(1)
.background(WidthPreferenceSettingView())
Text("John Smith")
}
HStack {
Text("20. ")
.frame(width: width, alignment: .leading)
.lineLimit(1)
.background(WidthPreferenceSettingView())
Text("Jane Done")
}
HStack {
Text("2000. ")
.frame(width: width, alignment: .leading)
.lineLimit(1)
.background(WidthPreferenceSettingView())
Text("Jax Dax")
}
}.onPreferenceChange(WidthPreferenceKey.self) { preferences in
for p in preferences {
let oldWidth = self.width ?? CGFloat.zero
if p.width > oldWidth {
self.width = p.width
}
}
}
}
}
如果您有多列数据,一种扩展方法是对列进行枚举或对它们进行索引,并且宽度的@State 将成为一个字典,其中每个键都是一列并.onPreferenceChange
与键值进行比较列的最大宽度。
为了显示结果,这是打开较大文本后的样子,就像一个魅力:)。
这篇关于 PreferenceKey 和检查视图树的文章非常有帮助:https ://swiftui-lab.com/communicating-with-the-view-tree-part-1/
推荐阅读
- sql-server - SQL Server - 编写一个查询,将周五->周四的周数据分组
- javascript - 如何在js中获取数组的非重复索引?
- django - Firebase 与 Django REST 的集成
- mongodb - 如何在 MongoDB 中选择两级模型的平面结构?
- regex - 是否可以从 NiFi 中的 CSV 文件标题名称中删除空格?
- r - 将项目粘贴到某些项目包含矢量的列表中
- c# - 如何从 C# 调用 mono_threads_request_thread_dump()?
- java - 将 .equals() 替换为 Objects.equals()
- php - 当属性不存在时,为什么 Twig 会退回到对象?
- angular - ngx-bootstrap 与 bootstrap3 设置工具提示宽度