我的问题是(在SwiftUI中)我有一个带有foreach的ScrollView。知道foreach何时加载所有我的条目,我希望最后一个条目集中。
我做了一些Google研究,但找不到任何答案。
ScrollView {
VStack {
ForEach (0..<self.entries.count) { index in
Group {
Text(self.entries[index].getName())
}
}
}
}
答案 0 :(得分:10)
我还没有足够的声望来发表评论,所以你去@Dam 和@Evert
要在 ForEach
中的条目数量发生变化时滚动到底部,您还可以使用与 ScrollViewReader
相同的方法,如上述答案中所述,通过像这样添加视图修饰符 onChange
:
struct ContentView: View {
let colors: [Color] = [.red, .blue, .green]
var entries: [Entry] = Array(repeating: Entry(), count: 10)
var body: some View {
ScrollView {
ScrollViewReader { value in
ForEach(0..<entries.count) { i in
Text(self.entries[i].getName())
.frame(width: 300, height: 200)
.background(colors[i % colors.count])
.padding(.all, 20)
}
.onChange(of: entries.count) { _ in
value.scrollTo(entries.count - 1)
}
}
}
}
}
答案 1 :(得分:8)
ScrollViewReader
的iOS14解决方案 SwiftUI获得了一项新功能。为了能够在ScrollView中滚动到特定位置。有一种名为ScrollViewReader
的新类型,其作用类似于Geometry Reader
。
下面的代码将滚动到视图中的最后一项。我重用了您的代码,并添加了一些颜色以实现更好的可视化效果。所以我猜这是您的“ Entry”结构:
struct Entry {
static var index = 0
var name = "Entry number "
func getName() -> String {
Entry.index += 1
return self.name + "\(Entry.index)"
}
}
主要的ContentView:
struct ContentView: View {
let colors: [Color] = [.red, .blue, .green]
var entries: [Entry] = Array(repeating: Entry(), count: 10)
var body: some View {
ScrollView {
ScrollViewReader { value in
ForEach(0..<entries.count) { i in
Text(self.entries[i].getName())
.frame(width: 300, height: 200)
.background(colors[i % colors.count])
.padding(.all, 20)
}
.onAppear {
value.scrollTo(entries.count - 1, anchor: .center)
}
}
}
}
}
尝试在WWDC20宣布的新版SwiftUI中运行此命令。我认为这是一个很大的增强。
答案 2 :(得分:1)
根据 Apple 的 documentation on ScrollViewReader
,它应该包装滚动视图,而不是嵌套。
来自 Apple 文档的示例:
@Namespace var topID
@Namespace var bottomID
var body: some View {
ScrollViewReader { proxy in
ScrollView {
Button("Scroll to Bottom") {
withAnimation {
proxy.scrollTo(bottomID)
}
}
.id(topID)
VStack(spacing: 0) {
ForEach(0..<100) { i in
color(fraction: Double(i) / 100)
.frame(height: 32)
}
}
Button("Top") {
withAnimation {
proxy.scrollTo(topID)
}
}
.id(bottomID)
}
}
}
func color(fraction: Double) -> Color {
Color(red: fraction, green: 1 - fraction, blue: 0.5)
}
This other article 还展示了如何使用 ScrollViewReader
来包装 List
元素,这也很方便。文章中的代码示例:
ScrollViewReader { scrollView in
List {
ForEach(photos.indices) { index in
Image(photos[index])
.resizable()
.scaledToFill()
.cornerRadius(25)
.id(index)
}
}
.
.
.
}
对我来说,使用 value.scrollTo(entries.count - 1)
不起作用。此外,使用 value.scrollTo(entries.last?.id)
也不起作用,直到我使用
.id(...)
视图修饰符(可能是因为我的条目不符合 Identifiable
)。
使用 ForEach
,这是我正在处理的代码:
ScrollViewReader { value in
ScrollView {
ForEach(state.messages, id: \.messageId) { message in
MessageView(message: message)
.id(message.messageId)
}
}
.onAppear {
value.scrollTo(state.messages.last?.messageId)
}
.onChange(of: state.messages.count) { _ in
value.scrollTo(state.messages.last?.messageId)
}
}
使用 onAppear
时的一个重要注意事项是在 ScrollView
/List
上使用该修饰符,而不是在 ForEach
中使用。在 ForEach
中执行此操作将导致它在手动滚动时触发列表中的元素。