表单中的 SwiftUI 选择器 - 无法动态调整表单大小 Space
SwiftUI Picker in Form - Can't Dynamically Size the Form Space
我正在为一个视图而苦苦挣扎,我想在其中嵌入多个选择器
其他意见。当我将选择器包装在一个表单中时,我得到了所需的行为
选择器,但在选择器周围有很多额外的 space 我似乎看不到
自动调整。
这是一个例子-红色轮廓中的space似乎是由另一个决定的
查看元素不是选择器的大小。
我当然可以硬编码窗体的框架高度,但这是反复试验
并且只会特定于设备和方向。我试过多次
Stacks inside Stacks with padding, GeometryReader 等版本,但我还没有想出任何
解决方案。顺便说一句,我确实想要选择器标签,否则我可以删除
表格。
我也尝试在 init() 中设置 UITableView.appearance().tableFooterView,但这也不起作用。
这是一个简化版本:
struct ContentView4: View {
@State var selectedNumber1: Int = 1
@State var selectedNumber2: Int = 2
@State var selectedNumber3: Int = 3
var body: some View {
NavigationView {
VStack(alignment: .leading) {
HStack {
Spacer()
Text("Compare up to 3")
.font(.caption)
Spacer()
}//h
Form {//for pickers
Picker(selection: $selectedNumber1, label: Text("A")) {
ForEach(0..<10) {
Text("\([=11=])")
}
}//picker
Picker(selection: $selectedNumber2, label: Text("B")) {
ForEach(0..<10) {
Text("\([=11=])")
}
}//picker
Picker(selection: $selectedNumber3, label: Text("C")) {
ForEach(0..<10) {
Text("\([=11=])")
}
}//picker
}//form for pickers
.padding(.horizontal, 10)
//.frame(height: 200) //don't want to hard code this
VStack(alignment: .leading) {
HStack {
Text("A")
.frame(width: 100)
Text("B")
.frame(width: 100)
Text("C")
.frame(width: 100)
}
.padding(.horizontal, 10)
ScrollView(.vertical, showsIndicators: false) {
VStack(alignment: .leading){
Text("A title line")
.font(.headline)
.padding(.vertical, 5)
HStack {
Text("Number")
.frame(width: 100)
Text("Number")
.frame(width: 100)
Text("Number")
.frame(width: 100)
}
Text("Another title line")
.font(.headline)
.padding(.vertical, 5)
HStack {
Text("Something")
.frame(width: 100)
Text("Something")
.frame(width: 100)
Text("Something")
.frame(width: 100)
}
Text("A Third title line")
.font(.headline)
.padding(.vertical, 5)
HStack {
Text("More")
.frame(width: 100)
Text("More")
.frame(width: 100)
Text("More")
.frame(width: 100)
}
}
}//scroll
.padding(.horizontal, 10)
}
.navigationBarTitle("Compare Three", displayMode: .inline)
}
}//nav
}//body
}//struct
有趣的是,我能够通过删除表单并包装每个表单来获得解决方案
菜单中的选择器,如下所示:
Menu {
Picker(selection: $selectedNumber2, label: EmptyView()) {
ForEach(0..<10) {
Text("\([=12=])")
}
}//picker
} label: {
HStack {
Text("B")
Spacer()
Image(systemName: "chevron.right")
.resizable()
.frame(width: 14, height: 14)
}//h
}//menu label
不过,如果能自动配置的话,我还是比较喜欢这个Form的样子
space 围绕表单项。
如有任何指导,我们将不胜感激。 Xcode13.4,iOS15.5
Form
(和 List
)并不意味着像这样堆叠在其他视图中,这就是为什么它有如此奇怪的行为。
幸运的是,使用 NavigationLink
重新创建您想要的内容相当简单。这是几个自定义视图的简单示例:
// drop-in NavigationLink replacement for Picker
struct NavigationButton<Content: View, SelectionValue: Hashable> : View {
@Binding var selection: SelectionValue
@ViewBuilder let content: () -> Content
@ViewBuilder let label: () -> Text
var body: some View {
NavigationLink {
PickerView(selection: $selection, content: content, label: label)
} label: {
HStack {
label()
Spacer()
Text(String(describing: selection))
.foregroundColor(.secondary)
}
.contentShape(Rectangle())
}
.buttonStyle(NavigationLinkButtonStyle())
}
}
// subview for the Picker page, which lets us use `dismiss()`
// to pop the subview when the user selects an option
struct PickerView<Content: View, SelectionValue: Hashable> : View {
@Binding var selection: SelectionValue
@ViewBuilder let content: () -> Content
@ViewBuilder let label: () -> Text
@Environment(\.dismiss) private var dismiss
var body: some View {
Form {
Picker(selection: $selection, content: content, label: label)
.pickerStyle(.inline)
.labelsHidden()
.onChange(of: selection) { _ in
dismiss()
}
}
.navigationTitle(label())
}
}
// recreate the appearance of a List row
struct NavigationLinkButtonStyle: ButtonStyle {
func makeBody(configuration: Configuration) -> some View {
HStack {
configuration.label
.frame(maxWidth: .infinity)
Image(systemName: "chevron.right")
.font(.footnote.bold())
.foregroundColor(Color(UIColor.tertiaryLabel))
}
.padding()
.background(
Rectangle()
.fill(configuration.isPressed ? Color(UIColor.quaternaryLabel) : Color(UIColor.systemBackground))
)
}
}
如果您喜欢使用 Form
得到的 .insetGrouped
样式,我们可以通过将 NavigationButton
放入剪裁的 VStack
:
来复制它
VStack(spacing: 0) {
NavigationButton(selection: $selectedNumber1) {
ForEach(0..<10) {
Text("\([=11=])")
}
} label: {
Text("A")
}
Divider()
NavigationButton(selection: $selectedNumber2) {
ForEach(0..<10) {
Text("\([=11=])")
}
} label: {
Text("B")
}
}
.clipShape(RoundedRectangle(cornerRadius: 11))
.padding()
.background(Color(UIColor.systemGroupedBackground))
这是一张屏幕截图,显示了我在您的原始视图上方的自定义视图 Form
。
(如果您喜欢 Picker 作为弹出菜单,您可以使用 Menu 而不是 NavigationLink)
我正在为一个视图而苦苦挣扎,我想在其中嵌入多个选择器 其他意见。当我将选择器包装在一个表单中时,我得到了所需的行为 选择器,但在选择器周围有很多额外的 space 我似乎看不到 自动调整。
这是一个例子-红色轮廓中的space似乎是由另一个决定的 查看元素不是选择器的大小。
我当然可以硬编码窗体的框架高度,但这是反复试验 并且只会特定于设备和方向。我试过多次 Stacks inside Stacks with padding, GeometryReader 等版本,但我还没有想出任何 解决方案。顺便说一句,我确实想要选择器标签,否则我可以删除 表格。
我也尝试在 init() 中设置 UITableView.appearance().tableFooterView,但这也不起作用。
这是一个简化版本:
struct ContentView4: View {
@State var selectedNumber1: Int = 1
@State var selectedNumber2: Int = 2
@State var selectedNumber3: Int = 3
var body: some View {
NavigationView {
VStack(alignment: .leading) {
HStack {
Spacer()
Text("Compare up to 3")
.font(.caption)
Spacer()
}//h
Form {//for pickers
Picker(selection: $selectedNumber1, label: Text("A")) {
ForEach(0..<10) {
Text("\([=11=])")
}
}//picker
Picker(selection: $selectedNumber2, label: Text("B")) {
ForEach(0..<10) {
Text("\([=11=])")
}
}//picker
Picker(selection: $selectedNumber3, label: Text("C")) {
ForEach(0..<10) {
Text("\([=11=])")
}
}//picker
}//form for pickers
.padding(.horizontal, 10)
//.frame(height: 200) //don't want to hard code this
VStack(alignment: .leading) {
HStack {
Text("A")
.frame(width: 100)
Text("B")
.frame(width: 100)
Text("C")
.frame(width: 100)
}
.padding(.horizontal, 10)
ScrollView(.vertical, showsIndicators: false) {
VStack(alignment: .leading){
Text("A title line")
.font(.headline)
.padding(.vertical, 5)
HStack {
Text("Number")
.frame(width: 100)
Text("Number")
.frame(width: 100)
Text("Number")
.frame(width: 100)
}
Text("Another title line")
.font(.headline)
.padding(.vertical, 5)
HStack {
Text("Something")
.frame(width: 100)
Text("Something")
.frame(width: 100)
Text("Something")
.frame(width: 100)
}
Text("A Third title line")
.font(.headline)
.padding(.vertical, 5)
HStack {
Text("More")
.frame(width: 100)
Text("More")
.frame(width: 100)
Text("More")
.frame(width: 100)
}
}
}//scroll
.padding(.horizontal, 10)
}
.navigationBarTitle("Compare Three", displayMode: .inline)
}
}//nav
}//body
}//struct
有趣的是,我能够通过删除表单并包装每个表单来获得解决方案 菜单中的选择器,如下所示:
Menu {
Picker(selection: $selectedNumber2, label: EmptyView()) {
ForEach(0..<10) {
Text("\([=12=])")
}
}//picker
} label: {
HStack {
Text("B")
Spacer()
Image(systemName: "chevron.right")
.resizable()
.frame(width: 14, height: 14)
}//h
}//menu label
不过,如果能自动配置的话,我还是比较喜欢这个Form的样子 space 围绕表单项。
如有任何指导,我们将不胜感激。 Xcode13.4,iOS15.5
Form
(和 List
)并不意味着像这样堆叠在其他视图中,这就是为什么它有如此奇怪的行为。
幸运的是,使用 NavigationLink
重新创建您想要的内容相当简单。这是几个自定义视图的简单示例:
// drop-in NavigationLink replacement for Picker
struct NavigationButton<Content: View, SelectionValue: Hashable> : View {
@Binding var selection: SelectionValue
@ViewBuilder let content: () -> Content
@ViewBuilder let label: () -> Text
var body: some View {
NavigationLink {
PickerView(selection: $selection, content: content, label: label)
} label: {
HStack {
label()
Spacer()
Text(String(describing: selection))
.foregroundColor(.secondary)
}
.contentShape(Rectangle())
}
.buttonStyle(NavigationLinkButtonStyle())
}
}
// subview for the Picker page, which lets us use `dismiss()`
// to pop the subview when the user selects an option
struct PickerView<Content: View, SelectionValue: Hashable> : View {
@Binding var selection: SelectionValue
@ViewBuilder let content: () -> Content
@ViewBuilder let label: () -> Text
@Environment(\.dismiss) private var dismiss
var body: some View {
Form {
Picker(selection: $selection, content: content, label: label)
.pickerStyle(.inline)
.labelsHidden()
.onChange(of: selection) { _ in
dismiss()
}
}
.navigationTitle(label())
}
}
// recreate the appearance of a List row
struct NavigationLinkButtonStyle: ButtonStyle {
func makeBody(configuration: Configuration) -> some View {
HStack {
configuration.label
.frame(maxWidth: .infinity)
Image(systemName: "chevron.right")
.font(.footnote.bold())
.foregroundColor(Color(UIColor.tertiaryLabel))
}
.padding()
.background(
Rectangle()
.fill(configuration.isPressed ? Color(UIColor.quaternaryLabel) : Color(UIColor.systemBackground))
)
}
}
如果您喜欢使用 Form
得到的 .insetGrouped
样式,我们可以通过将 NavigationButton
放入剪裁的 VStack
:
VStack(spacing: 0) {
NavigationButton(selection: $selectedNumber1) {
ForEach(0..<10) {
Text("\([=11=])")
}
} label: {
Text("A")
}
Divider()
NavigationButton(selection: $selectedNumber2) {
ForEach(0..<10) {
Text("\([=11=])")
}
} label: {
Text("B")
}
}
.clipShape(RoundedRectangle(cornerRadius: 11))
.padding()
.background(Color(UIColor.systemGroupedBackground))
这是一张屏幕截图,显示了我在您的原始视图上方的自定义视图 Form
。
(如果您喜欢 Picker 作为弹出菜单,您可以使用 Menu 而不是 NavigationLink)