I want to get the list's offset to achieve pagination. So, I wrote like below.
- ContentView.swift
import SwiftUI
struct ContentView: View {
@State var list = ["item1" ,"item2" ,"item3", "item4" ,"item5" ,"item6" ,"item7" ,"item8" ,"item9" ,"item10" ,"item11" ,"item12"]
@State private var offset: CGFloat = 0
var body: some View {
NavigationView {
GeometryReader { outsideProxy in
List {
ForEach(list, id: \.self) { item in
ZStack {
GeometryReader { insideProxy in
Color.clear
.preference(key: ScrollOffsetPreferenceKey.self, value: [outsideProxy.frame(in: .global).minY - insideProxy.frame(in: .global).minY])
}
NavigationLink("\(item), \(self.offset)") {
Text("\(item), \(self.offset)")
}
.frame(height: 100)
}
.listRowInsets(EdgeInsets(top: 5, leading: 0, bottom: 5, trailing: 3))
}
}
.onPreferenceChange(ScrollOffsetPreferenceKey.self) { value in
self.offset = value[0]
}
.listStyle(PlainListStyle())
.navigationBarTitleDisplayMode(.inline)
.navigationTitle(Text("title"))
.toolbar(content: {
ToolbarItem(placement: .bottomBar) {
HStack {
Button("Add") {
list.insert("hello_\(Date.now.description)", at: 0)
}
Spacer()
Text("\(offset)")
}
}
})
}
}
}
}
struct ScrollOffsetPreferenceKey: PreferenceKey {
typealias Value = [CGFloat]
static var defaultValue: [CGFloat] = [0]
static func reduce(value: inout [CGFloat], nextValue: () -> [CGFloat]) {
value.append(contentsOf: nextValue())
}
}
However, when I press the Add button to add an element, the offset
value shifts.
I don't want the offset
to update because I want to add elements when I scroll further up at the top of the List.
Can anyone tell me how to add elements and not shift the offset
?
Thanks,
Addition 220419
I wrote a below code in reference to this
- List and ScrollView(body only)
var body: some View {
NavigationView {
List {
ScrollView {
VStack {
ForEach(list, id: \.self) { item in
NavigationLink("\(item), \(self.offset)") {
Text("hello\(item), \(self.offset)")
}
.frame(height: 100)
.onAppear {
print("appear: \(item)")
print(offset)
}
.listRowInsets(EdgeInsets(top: 5, leading: 0, bottom: 5, trailing: 3))
}
}
.background(GeometryReader {
Color.clear.preference(key: ViewOffsetKey.self, value: -$0.frame(in: .named("scroll")).origin.y)
})
.onPreferenceChange(ViewOffsetKey.self) {
self.offset = $0
}
}
.navigationBarTitleDisplayMode(.inline)
.navigationTitle(Text("title"))
.toolbar(content: {
ToolbarItem(placement: .bottomBar) {
HStack {
Text("\(thre)")
Spacer()
Button("Add") {
list.insert("hello_\(Date.now.description)", at: 0)
}
Spacer()
Text("\(offset)")
}
}
})
}
.coordinateSpace(name: "scroll")
.listStyle(PlainListStyle())
}
}
- List only(don't work)
var body: some View {
NavigationView {
List {
ForEach(list, id: \.self) { item in
NavigationLink("\(item), \(self.offset)") {
Text("hello\(item), \(self.offset)")
}
.frame(height: 100)
.onAppear {
print("appear: \(item)")
print(offset)
}
.listRowInsets(EdgeInsets(top: 5, leading: 0, bottom: 5, trailing: 3))
}
.background(GeometryReader {
Color.clear.preference(key: ViewOffsetKey.self, value: -$0.frame(in: .named("scroll")).origin.y)
})
.onPreferenceChange(ViewOffsetKey.self) {
self.offset = $0
}
}
.coordinateSpace(name: "scroll")
.navigationBarTitleDisplayMode(.inline)
.navigationTitle(Text("title"))
.toolbar(content: {
ToolbarItem(placement: .bottomBar) {
HStack {
Text("\(thre)")
Spacer()
Button("Add") {
list.insert("hello_\(Date.now.description)", at: 0)
}
Spacer()
Text("\(offset)")
}
}
})
.listStyle(PlainListStyle())
.onChange(of: offset) { newValue in
if lock { return }
self.lock = true
if newValue < -105 {
DispatchQueue.main.asyncAfter(deadline: DispatchTime.now() + 3) {
list.insert("hello_\(Date.now.description)", at: 0)
self.thre = newValue
self.lock = false
}
} else {
self.lock = false
}
}
}
}