我不断回到这个问题,对这里的任何答案都不满意。我发现有效的是创建一个自定义包装器来评估是否应该使用 ScrollView。这比我想象的要容易得多。
创建可预防的滚动视图
基本上我们想要一个可以切换滚动的自定义视图。使用绑定,任何使用我们视图的人都可以完全控制滚动功能。
请原谅我的命名,但 PreventableScrollView 是我能想到的全部:)
struct PreventableScrollView<Content>: View where Content: View {
@Binding var canScroll: Bool
var content: () -> Content
var body: some View {
if canScroll {
ScrollView(.vertical, showsIndicators: false, content: content)
} else {
content()
}
}
}
基本上我们需要做的就是决定是将内容嵌入到 ScrollView 中还是直接返回。很简单。
我创建了一个演示来展示它如何与动态内容一起使用以及随时切换的能力。当我添加项目时,它也会切换滚动。
如果你有兴趣,这里是代码。
struct DemoView: View {
@State private var canScroll: Bool = false
let allColors: [UIColor] = [.purple, .systemPink, .systemGreen, .systemBlue, .black, .cyan, .magenta, .orange, .systemYellow, .systemIndigo, .systemRed]
@State var colors: [UIColor] = [.white]
var body: some View {
VStack {
Spacer()
VStack {
PreventableScrollView(canScroll: $canScroll) {
ForEach(colors.indices, id: \.self) { index in
Rectangle().fill().foregroundColor(Color(colors[index]))
.frame(height: 44)
.cornerRadius(8)
}
}.fixedSize(horizontal: false, vertical: true)
HStack {
Spacer()
Toggle(isOn: $canScroll, label: {
Text("Toggle Scroll")
}).toggleStyle(SwitchToggleStyle(tint: .orange))
}.padding(.top)
}
.textFieldStyle(RoundedBorderTextFieldStyle())
.padding()
.background(Rectangle().fill().foregroundColor(Color(UIColor.secondarySystemFill)).cornerRadius(8))
HStack {
Button(action: {
addField()
}, label: {
Image(systemName: "plus")
}).padding()
}
}
.padding()
}
func addField() {
canScroll.toggle()
colors.append(allColors.randomElement()!)
}
}