有很多解决方案可以尝试使用 VStack 内的 HStack 在 SwiftUI 中对齐多个图像和文本。有什么办法可以实现多个标签吗?添加到列表中时,多个标签会自动垂直对齐。当它们嵌入到 VStack 中时,是否有一种简单的方法可以做到这一点?
struct ContentView: View {
var body: some View {
// List{
VStack(alignment: .leading){
Label("People", systemImage: "person.3")
Label("Star", systemImage: "star")
Label("This is a plane", systemImage: "airplane")
}
}
}
Run Code Online (Sandbox Code Playgroud)
rob*_*off 17
所以,你想要这个:
\n\n我们将实现一个名为 的容器视图,EqualIconWidthDomain以便我们可以使用以下代码绘制上面显示的图像:
struct ContentView: View {\n var body: some View {\n EqualIconWidthDomain {\n VStack(alignment: .leading) {\n Label("People", systemImage: "person.3")\n Label("Star", systemImage: "star")\n Label("This is a plane", systemImage: "airplane")\n }\n }\n }\n}\nRun Code Online (Sandbox Code Playgroud)\n您可以在这个要点中找到所有代码。
\n为了解决这个问题,我们需要测量每个图标的宽度,并frame使用宽度的最大值将 a 应用于每个图标。
SwiftUI 提供了一个名为 \xe2\x80\x9cpreferences\xe2\x80\x9d 的系统,视图可以通过该系统将值传递给其祖先,而祖先可以聚合这些值。为了使用它,我们创建一个符合以下条件的类型PreferenceKey,如下所示:
fileprivate struct IconWidthKey: PreferenceKey {\n static var defaultValue: CGFloat? { nil }\n\n static func reduce(value: inout CGFloat?, nextValue: () -> CGFloat?) {\n switch (value, nextValue()) {\n case (nil, let next): value = next\n case (_, nil): break\n case (.some(let current), .some(let next)): value = max(current, next)\n }\n }\n}\nRun Code Online (Sandbox Code Playgroud)\n为了将最大宽度传递回标签,我们将使用 \xe2\x80\x9cenvironment\xe2\x80\x9d 系统。为此,我们需要一个EnvironmentKey. 在这种情况下,我们可以IconWidthKey再次使用。我们还需要添加一个EnvironmentValues使用键类型的计算属性:
extension IconWidthKey: EnvironmentKey { }\n\nextension EnvironmentValues {\n fileprivate var iconWidth: CGFloat? {\n get { self[IconWidthKey.self] }\n set { self[IconWidthKey.self] = newValue }\n }\n}\nRun Code Online (Sandbox Code Playgroud)\n现在我们需要一种方法来测量图标的宽度,将其存储在首选项中,并将环境的宽度应用于图标。我们将创建一个ViewModifier来执行这些步骤:
fileprivate struct IconWidthModifier: ViewModifier {\n @Environment(\\.iconWidth) var width\n\n func body(content: Content) -> some View {\n content\n .background(GeometryReader { proxy in\n Color.clear\n .preference(key: IconWidthKey.self, value: proxy.size.width)\n })\n .frame(width: width)\n }\n}\nRun Code Online (Sandbox Code Playgroud)\n要将修饰符应用于每个标签的图标,我们需要一个LabelStyle:
struct EqualIconWidthLabelStyle: LabelStyle {\n func makeBody(configuration: Configuration) -> some View {\n HStack {\n configuration.icon.modifier(IconWidthModifier())\n configuration.title\n }\n }\n}\nRun Code Online (Sandbox Code Playgroud)\n最后我们就可以编写EqualIconWidthDomain容器了。它需要从 SwiftUI 接收偏好值并将其放入其后代的环境中。它还需要将 应用于EqualIconWidthLabelStyle其后代。
struct EqualIconWidthDomain<Content: View>: View {\n let content: Content\n @State var iconWidth: CGFloat? = nil\n\n init(@ViewBuilder _ content: () -> Content) {\n self.content = content()\n }\n\n var body: some View {\n content\n .environment(\\.iconWidth, iconWidth)\n .onPreferenceChange(IconWidthKey.self) { self.iconWidth = $0 }\n .labelStyle(EqualIconWidthLabelStyle())\n }\n}\nRun Code Online (Sandbox Code Playgroud)\n请注意,EqualIconWidthDomain不必是 a VStackof Labels,并且图标不必是 SF Symbols 图像。例如,我们可以展示这个:
请注意,标签 \xe2\x80\x9cicons\xe2\x80\x9d 之一是Text. 所有四个图标都以相同的宽度布局(跨两列)。这是代码:
struct FancyView: View {\n var body: some View {\n EqualIconWidthDomain {\n VStack {\n Text("Le Menu")\n .font(.caption)\n Divider()\n HStack {\n VStack(alignment: .leading) {\n Label(\n title: { Text("Strawberry") },\n icon: { Text("") })\n Label("Money", systemImage: "banknote")\n }\n VStack(alignment: .leading) {\n Label("People", systemImage: "person.3")\n Label("Star", systemImage: "star")\n }\n }\n }\n }\n }\n}\nRun Code Online (Sandbox Code Playgroud)\n
| 归档时间: |
|
| 查看次数: |
2811 次 |
| 最近记录: |