我试图将自定义HStack
行包含在SwiftUI Form
中,如下所示:
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()
}
结果是
但是,我希望Label
与Toggle
垂直对齐,Menu
垂直对齐按钮。
是否有为自定义HStack
行选择对齐模式的标准方法?
发布于 2022-10-04 10:57:53
仅限macOS 13
LabeledContent
在SwiftUI中的新视图将帮助您:
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的首选键代码的基础上,关键是使用对齐指南而不是填充。创建自定义视图,并使用仅测量宽度的自定义首选项:
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
。
发布于 2022-10-04 10:20:51
您可以将内容包装在VStack中,并使用其alignment
修饰符将所有内容对齐,例如:
VStack(对齐:.leading)
就像这样:
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()
}
参见这里的工作示例:
发布于 2022-10-04 10:39:20
macOS 13
LabeledContent {
HStack {
// ...
}
} label: {
Text("Count")
}
LabeledContent
这里的信息前一版本
思想:使用GeometryReader计算标签的大小,并按其宽度偏移视图。
@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
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
struct SizePreferenceKey: PreferenceKey {
static var defaultValue: CGSize = .zero
static func reduce(value: inout CGSize, nextValue: () -> CGSize) { }
}
Button(<#String#>) { <#Action#> }
而不是
Button(action: { <#Action#> }) { Text(<#String#>) }
https://stackoverflow.com/questions/73945767
复制相似问题