我通过@ChrisR的代码进行了调整,加入了一个hack,至少可以展示如何让scrollTo工作。它在两个几乎完全相同但id不同(其中一个有一点padding)的视图之间切换。
import SwiftUI
struct ContentView: View {
@State private var vmtext = "\n\n\n\nTest Text"
@State private var number = 0
@State private var id = 0
let timer = Timer.publish(every: 0.5, on: .main, in: .common).autoconnect()
var body: some View {
ScrollViewReader { proxy in
ScrollView {
id == 0 ?
VStack {
Text(vmtext)
.padding(.top, 0)
.font(.title2)
.id(0)
}
:
VStack {
Text(vmtext)
.padding(.top, 1)
.font(.title2)
.id(1)
}
}
.onChange(of: vmtext) { newValue in
print("onChange entered. id: \(id)")
proxy.scrollTo(id, anchor: .bottom)
}
}
.frame(height: 90, alignment: .center)
.frame(maxWidth: .infinity)
.border(.primary)
.padding()
.onReceive(timer) { _ in
if id == 0 { id = 1} else {id = 0}
number += 1
vmtext += " word\(number)"
}
}
}
注意:
如果显示的文本视图的高度没有改变,则proxy.scrollTo将被忽略。将填充设置为相同,hack就会失效。
从var vmtext中删除"\n\n\n\n"会破坏hack。它们使文本视图的初始大小大于滚动视图窗口,因此立即可滚动-或者什么都可以:-)。如果您删除它们,则在用手指进行初始滚动后,滚动将开始工作。
编辑:
这是一个没有填充和"\n\n\n\n" hack的版本,它使用双旋转hack。
import SwiftUI
struct ContentView: View {
@State private var vmtext = "Test Text"
@State private var number = 0
@State private var id = 0
let timer = Timer.publish(every: 0.3, on: .main, in: .common).autoconnect()
var body: some View {
ScrollViewReader { proxy in
ScrollView {
Group {
id == 0 ?
VStack {
Text(vmtext)
.font(.title2)
.id(0)
}
:
VStack {
Text(vmtext)
.font(.title2)
.id(1)
}
}
.padding()
.rotationEffect(Angle(degrees: 180))
}
.rotationEffect(Angle(degrees: 180))
.onChange(of: vmtext) { newValue in
withAnimation {
if id == 0 { id = 1 } else { id = 0 }
proxy.scrollTo(id, anchor: .bottom)
}
}
}
.frame(height: 180, alignment: .center)
.frame(maxWidth: .infinity)
.border(.primary)
.padding()
.onReceive(timer) { _ in
number += 1
vmtext += " word\(number)"
}
}
}
如果文本从视图顶部开始,并且只有在文本填满视图时才滚动,就像SwiftUI TextEditor一样,那将是很好的...但是withAnimation不起作用。