gpt4 book ai didi

swiftui - 如何增加 SwiftUI 选择器中显示的最大行数?

转载 作者:行者123 更新时间:2023-12-02 14:48:46 25 4
gpt4 key购买 nike

我正在尝试创建一个 SwiftUI 选择器,用户可以使用它来选择 1000 到 20000 之间的数字(以 1000 为增量。例如 1000,2000,3000 .... ... 20000)

默认情况下,SwiftUI 选择器只能容纳 10 行文本。如何允许 SwiftUI 选择器包含 20 行文本?

最佳答案

我猜你写的是这样的:

struct ContentView: View {
var body: some View {
Picker(selection: $value, label: Text("Pick One")) {
Text("1000").tag(1000)
Text("2000").tag(2000)
Text("3000").tag(3000)
Text("4000").tag(4000)
Text("5000").tag(5000)
Text("6000").tag(6000)
Text("7000").tag(7000)
Text("8000").tag(8000)
Text("9000").tag(9000)
Text("10000").tag(10000)
}
}

@State var value: Int = 1000
}

然后您尝试为 11000 添加一行并收到此错误:

error: picker.xcplaygroundpage:5:31: error: cannot convert value of type 'Binding<Int>' to expected argument type 'Binding<_>'
Picker(selection: $value, label: Text("Pick One")) {
^~~~~~

问题在于,由于 Swift 语言和 SwiftUI 实现方式的限制,您只能在 @ViewBuilder 主体中拥有 10 个 subview 。

这里有两种方法可以解决这个问题。

一种适合您的设计的方法是使用 ForEach:

struct ContentView: View {
var body: some View {
Picker(selection: $value, label: Text("Pick One")) {
ForEach(Array(stride(from: 1000, through: 20000, by: 1000))) { number in
Text("\(number)").tag(number)
}
}
}

@State var value: Int = 1000
}

如果您的项目不遵循简单的模式,另一种方法会更合适,即使用 Group 对您的项目进行分组:

struct ContentView: View {
var body: some View {
Picker(selection: $value, label: Text("Pick One")) {
Group {
Text("1000").tag(1000)
Text("2000").tag(2000)
Text("3000").tag(3000)
Text("4000").tag(4000)
Text("5000").tag(5000)
Text("6000").tag(6000)
Text("7000").tag(7000)
Text("8000").tag(8000)
Text("9000").tag(9000)
Text("10000").tag(10000)
}
Group {
Text("11000").tag(11000)
Text("12000").tag(12000)
Text("13000").tag(13000)
Text("14000").tag(14000)
Text("15000").tag(15000)
Text("16000").tag(16000)
Text("17000").tag(17000)
Text("18000").tag(18000)
Text("19000").tag(19000)
Text("20000").tag(20000)
}
}
}

@State var value: Int = 1000
}

SwiftUI 将 Group subview 展平到 Group 的父 View 中(在本例中,到 Picker 中)。每个 Group 最多可以有 10 个 subview ,它们本身可以是 Group,因此通过嵌套 Group,您可以在其中包含任意多个显式元素你的选择器。但我建议使用 ForEach

如果您想了解 10 个 subview 限制的来源,请编辑我的第二个示例,将 Picker 存储在这样的变量中:

struct ContentView: View {
var body: some View {
let picker = Picker(selection: $value, label: Text("Pick One")) {
Group {
...
}
}
return picker
}
}

现在按住 option 键并单击 Xcode 中的 picker 变量以查看其推断类型:

inferred type of picker

让我们重新格式化它以使其更具可读性:

let picker: Picker<
Text,
Int,
TupleView<(
Group<TupleView<(
some View,
some View,
some View,
some View,
some View,
some View,
some View,
some View,
some View,
some View)>>,
Group<TupleView<(
some View,
some View,
some View,
some View,
some View,
some View,
some View,
some View,
some View,
some View)>>)>>

哇,好大的类型! SwiftUI 大量使用此类泛型类型,因为它在运行时效率更高。因为这些都是符合 Viewstruct 类型,Swift 将整个 Picker 及其所有子项存储在一个连续的内存块中。该 block 可以从堆栈开始,仅当 SwiftUI 最终需要对其进行类型删除或长期存储时才需要将其复制到堆中。与 UIKit 相比,其中每个 View 在创建时总是单独分配在堆上。

ViewBuilder是组装这些复杂 View 的 SwiftUI 实用程序。 Swift 将每个 Group 的主体转换为对 ViewBuilder.buildBlock 的调用,Group 主体中的每个 View 作为 的单独参数>ViewBuilder.buildBlock。这些参数中的每一个都可以是一个单独的类型(例如,一个 Group 可以有一些 Text 子级和一些 Image 子级)。但是 Swift 不支持可变参数泛型,所以 ViewBuilder 必须定义一个采用单个 View 的 buildBlock 版本,一个采用两个 View 的版本,以及一个采用两个 View 的版本采用三 View ,依此类推。它不能定义无限多的方法,因为那样的话 SwiftUI 框架就会无限大。所以它在 10 个参数处停止:

static func buildBlock() -> EmptyView
Builds an empty view from a block containing no statements.

static func buildBlock<Content>(Content) -> Content
Passes a single view written as a child view through unmodified.

static func buildBlock<C0, C1>(C0, C1) -> TupleView<(C0, C1)>
static func buildBlock<C0, C1, C2>(C0, C1, C2) -> TupleView<(C0, C1, C2)>
static func buildBlock<C0, C1, C2, C3>(C0, C1, C2, C3) -> TupleView<(C0, C1, C2, C3)>
static func buildBlock<C0, C1, C2, C3, C4>(C0, C1, C2, C3, C4) -> TupleView<(C0, C1, C2, C3, C4)>
static func buildBlock<C0, C1, C2, C3, C4, C5>(C0, C1, C2, C3, C4, C5) -> TupleView<(C0, C1, C2, C3, C4, C5)>
static func buildBlock<C0, C1, C2, C3, C4, C5, C6>(C0, C1, C2, C3, C4, C5, C6) -> TupleView<(C0, C1, C2, C3, C4, C5, C6)>
static func buildBlock<C0, C1, C2, C3, C4, C5, C6, C7>(C0, C1, C2, C3, C4, C5, C6, C7) -> TupleView<(C0, C1, C2, C3, C4, C5, C6, C7)>
static func buildBlock<C0, C1, C2, C3, C4, C5, C6, C7, C8>(C0, C1, C2, C3, C4, C5, C6, C7, C8) -> TupleView<(C0, C1, C2, C3, C4, C5, C6, C7, C8)>
static func buildBlock<C0, C1, C2, C3, C4, C5, C6, C7, C8, C9>(C0, C1, C2, C3, C4, C5, C6, C7, C8, C9) -> TupleView<(C0, C1, C2, C3, C4, C5, C6, C7, C8, C9)>

这就是为什么任何内容使用 ViewBuilder 定义的 View (包括 VStackHStackZStackPickerListGroup 等)只能有 10 个直接 subview 。

关于swiftui - 如何增加 SwiftUI 选择器中显示的最大行数?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/57173197/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com