Reputation: 281
I have a class which is set up to trigger movement functions in a member variable UICollectionView :
class CollectionFunctionStore : ObservableObject {
//class to hold data about a UICollection and from where some functions can be triggered
var collectionRef : UICollectionView?
func jumpGrid(){
if let lclCollection = collectionRef {
let ip = IndexPath(row: 15, section: 0)
lclCollection.scrollToItem(at: ip, at: .bottom, animated: false)
lclCollection.reloadData()
print("jumpGrid() was reached: ")
}
}
}
the single function there "jumpGrid" will bounce the grid down to the 15th row this class is being used in a swiftUI app and the collection in question is contained in a UIViewRepresentable. Both the function store and the UIViewRepresentable containing the UICollectionView are in a struct along with a button in the top level content view
import SwiftUI
struct ContentView: View {
@ObservedObject var swiperStore = CollectionFunctionStore()
var body: some View {
return ZStack {
VStack{
CollectionAndStoreContainer(swiperStore: swiperStore)
JumpButton(swiperStore: swiperStore)
}.onAppear(perform: swiperStore.jumpGrid)
}
}
}
struct CollectionAndStoreContainer : View {
@ObservedObject var swiperStore : CollectionFunctionStore
var body: some View{
return ZStack{
CollectionViewRepresentable(swiperStoreParam: swiperStore).frame(width: 30, height: 200)
}
}
}
struct JumpButton : View {
@ObservedObject var swiperStore : CollectionFunctionStore
var body : some View{
return Button(action: {
swiperStore.jumpGrid()
}){
ZStack {
Rectangle().frame(width: 60, height: 30).foregroundColor(.orange).cornerRadius(4)
Text("j").foregroundColor(.white)
}
}
}
}
The problem Im facing is this: the button which contains the same function store as the top level view can trigger the scroll to item function without any problem, whereas the onAppear event can call the function and it will actually print the message contained in its code but it does not move the content of the collection... Button calls the function and the UICollectionView responds properly onAppear calls the function but the UICollectionView does not move.
=====Some additional info===== I do not have a choice in the use of UIViewRepresentable in this situation, I cant use lazyHgrid or HStacks also here is the code of the UIViewRepresentable in question
struct CollectionViewRepresentable : UIViewRepresentable {
var swiperStore : CollectionFunctionStore
typealias UIViewType = UICollectionView
init(swiperStoreParam : CollectionFunctionStore) {
swiperStore = swiperStoreParam
}
func makeUIView(context: Context) -> UICollectionView {
let layout = UICollectionViewFlowLayout()
layout.scrollDirection = .vertical
layout.itemSize = CGSize(width: 30, height: 30)
layout.sectionInset = UIEdgeInsets(top: 0, left: 0, bottom: 0, right: 0)
layout.minimumLineSpacing = 0
let collectionView = UICollectionView(frame: .zero, collectionViewLayout: layout)
collectionView.dataSource = context.coordinator
collectionView.delegate = context.coordinator
collectionView.register(ExtendedCell.self, forCellWithReuseIdentifier: "ExtCell")
collectionView.isScrollEnabled = true
collectionView.showsHorizontalScrollIndicator = false
collectionView.showsVerticalScrollIndicator = false
swiperStore.collectionRef = collectionView
return collectionView
}
func makeCoordinator() -> Coordinator {
return Coordinator()
}
func updateUIView(_ uiView: UICollectionView, context: Context) {
}
}
anyone any ideas? The overall goal is to get the UICollectionView to scroll to a specific location at the very start of its appearance so I thought that using onAppear in SwiftUI was the best way to go, but for some reason it's not moving the grid, is there even a better option in the Coordinator for example? Any help appreciated..
Upvotes: 1
Views: 698
Reputation: 258413
I think it is too early to call scroll-to in onAppear, because collection view has not finished construction yet at that time.
Try
}.onAppear {
DispatchQueue.main.async { swiperStore.jumpGrid() }
}
or even
}.onAppear {
// with some delay, if appeared constructed with animation or async, etc.
DispatchQueue.main.asyncAfter(deadline: .now() + 0.5) { // 0.25-0.5 sec
swiperStore.jumpGrid()
}
}
Upvotes: 1