首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >SwiftUI表单对齐macOS

SwiftUI表单对齐macOS
EN

Stack Overflow用户
提问于 2022-10-04 09:26:00
回答 3查看 193关注 0票数 1

我试图将自定义HStack行包含在SwiftUI Form中,如下所示:

代码语言:javascript
运行
复制
var body: some View {
    Form {
        TextField("Text", text: .constant("test"))
        Toggle("Toggle", isOn: .constant(true))
            .toggleStyle(SwitchToggleStyle())
        HStack {
            Text("Label")
            MenuButton("Menu") {
                Button(action: {
                    print("Clicked Pizza")
                }) { Text("Pizza") }
                Button(action: {
                    print("Clicked Pasta")
                }) { Text("Pasta") }
            }
            TextField("Topping", text: .constant("Cheese"))
                .labelsHidden()
        }
        
    }
    .padding()
}

结果是

但是,我希望LabelToggle垂直对齐,Menu垂直对齐按钮。

是否有为自定义HStack行选择对齐模式的标准方法?

EN

回答 3

Stack Overflow用户

回答已采纳

发布于 2022-10-04 10:57:53

仅限macOS 13

LabeledContent在SwiftUI中的新视图将帮助您:

代码语言:javascript
运行
复制
LabeledContent("Label") {
  MenuButton("Menu") {
    Button(action: {
      print("Clicked Pizza")
    }) { Text("Pizza") }
    Button(action: {
      print("Clicked Pasta")
    }) { Text("Pasta") }
  }
  TextField("Topping", text: .constant("Cheese"))
    .labelsHidden()
  }
}

但是,该视图尚未移植到macOS的早期版本,因此,如果需要支持早期版本,则需要另一种方法。

早期版本的macOS

在@Nhat Nguyen Duc的首选键代码的基础上,关键是使用对齐指南而不是填充。创建自定义视图,并使用仅测量宽度的自定义首选项:

代码语言:javascript
运行
复制
struct LabeledHStack<Content: View>: View {
    var label: String
    var content: () -> Content
    @State var labelWidth: CGFloat = 0

    init(_ label: String, @ViewBuilder content: @escaping () -> Content) {
        self.label = label
        self.content = content
    }

    var body: some View {
        HStack {
            Text(label)
                .readSize { self.labelWidth = $0 }
            content()
        }
        .alignmentGuide(.leading) { _ in labelWidth + 10 } // see note
    }
}

struct WidthPreferenceKey: PreferenceKey {
    static var defaultValue: CGFloat = 0
    static func reduce(value: inout CGFloat, nextValue: () -> CGFloat) { }
}

extension View {
    func readWidth(onChange: @escaping (CGFloat) -> Void) -> some View {
        background(
            GeometryReader { geometryProxy in
                Color.clear
                    .preference(key: WidthPreferenceKey.self, value: geometryProxy.size.width)
            }
        )
        .onPreferenceChange(WidthPreferenceKey.self, perform: onChange)
    }
}

注意,在自定义视图中,我添加了10个像素,以快速模拟标签与其表单元素之间的间距。可能有一种更好的方法来使这种功能适用于可访问性大小等(例如,使用@ScaledMetric值)。您也可能希望将此应用于填充,而不是在对齐指南计算中。

下面是macOS13 13的LabeledContent行,后面是LabeledHStack

票数 4
EN

Stack Overflow用户

发布于 2022-10-04 10:20:51

您可以将内容包装在VStack中,并使用其alignment修饰符将所有内容对齐,例如:

VStack(对齐:.leading)

就像这样:

代码语言:javascript
运行
复制
var body: some View {
    Form {
        VStack (alignment: .leading){
            TextField("Text", text: .constant("test"))
            Toggle("Toggle", isOn: .constant(true))
                .toggleStyle(SwitchToggleStyle())
            HStack {
                Text("Label")
                MenuButton("Menu") {
                    Button(action: {
                        print("Clicked Pizza")
                    }) { Text("Pizza") }
                    Button(action: {
                        print("Clicked Pasta")
                    }) { Text("Pasta") }
                }
                TextField("Topping", text: .constant("Cheese"))
                    .labelsHidden()
            }
            .frame(width: .infinity, height: .infinity)
        }
        
    }
    .padding()
}

参见这里的工作示例:

票数 2
EN

Stack Overflow用户

发布于 2022-10-04 10:39:20

macOS 13

代码语言:javascript
运行
复制
LabeledContent {
    HStack { 
        // ...
    }
} label: {
    Text("Count")
}
  • 阅读更多关于LabeledContent 这里的信息

前一版本

思想:使用GeometryReader计算标签的大小,并按其宽度偏移视图。

代码语言:javascript
运行
复制
@State private var textSize = CGSize.zero

var body: some View {
    Form {
        TextField("Text", text: .constant("test"))
            .padding(.leading, -textSize.width)
        Toggle("Toggle", isOn: .constant(true))
            .toggleStyle(SwitchToggleStyle())
            .padding(.leading, -textSize.width)
        HStack {
            Text("Label")
                .readSize { textSize in
                    self.textSize = textSize
                }
            MenuButton("Menu") {
                Button("Pizza") {
                    print("Clicked Pizza")
                }
                Button("Pasta") {
                    print("Clicked Pasta")
                }
            }
            TextField("Topping", text: .constant("Cheese"))
                .labelsHidden()
        }
        .padding(.leading, -textSize.width - 10)
        .frame(maxWidth: .infinity)
    }
    .padding(.leading, textSize.width + 10)
    .padding()
}
  • extension View
代码语言:javascript
运行
复制
extension View {
    func readSize(onChange: @escaping (CGSize) -> Void) -> some View {
        background(
            GeometryReader { geometryProxy in
                Color.clear
                    .preference(key: SizePreferenceKey.self, value: geometryProxy.size)
            }
        )
        .onPreferenceChange(SizePreferenceKey.self, perform: onChange)
    }
}
  • struct SizePreferenceKey
代码语言:javascript
运行
复制
struct SizePreferenceKey: PreferenceKey {
    static var defaultValue: CGSize = .zero
    static func reduce(value: inout CGSize, nextValue: () -> CGSize) { }
}
  • 奖励:用于只包含标签的按钮,您可以使用
代码语言:javascript
运行
复制
Button(<#String#>) { <#Action#> }

而不是

代码语言:javascript
运行
复制
Button(action: { <#Action#> }) { Text(<#String#>) }
票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/73945767

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档