Uicollectionview Compositionallayout Not Calling Uiscrolldelegate

UICollectionView CompositionalLayout not calling UIScrollDelegate

The answer is using the visibleItemsInvalidationHandler closure on the section (NSCollectionLayoutSection).

This handler receives updates whenever an event results in an animation. It operates similar to scrollViewDidScroll and on horizontal scrolling groups it will be passed all the items, the scroll view offset and the NSCollectionLayoutEnvironment.

https://developer.apple.com/documentation/uikit/nscollectionlayoutsection/3199096-visibleitemsinvalidationhandler

Example:

section.visibleItemsInvalidationHandler = { [weak self] visibleItems, point, environment in
self?.currentIndex = visibleItems.last?.indexPath.row
}

Swift 5: scrollViewDidScroll not called in UICollectionView class

Add in viewDidLoad. scroll function related to UICollectionViewDelegate and you need to set the delegate for using your override functions

section.visibleItemsInvalidationHandler = { [weak self] visibleItems, point, environment in
self?.pager.currentPage = visibleItems.last!.indexPath.row
}

UICollectionView delegate is not responding when the UICollectionView is embedded within a UIScrollView

Having written the question I worked out my issue.

As part of the layout within the first half of the screen, I have a UITapGestureRecognizer added to the UIScrollView to endEditing() should the user click outside of a UITextField. This tap gesture was receiving the tap and 'ending it' before it was passed to the UICollectionView.

implementing UIScrollViewDelegate in a UICollectionView subclass

You can add a function that implement the default code you need, for example:

class YourCollectionView: UICollectionView {

override init(frame: CGRect, collectionViewLayout layout: UICollectionViewLayout) {
super.init(frame: frame, collectionViewLayout: layout)
}

required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}

func updateUIOnScrollViewDidScroll(_ scrollView: UIScrollView) {
//...
}
}

Then when you implement the delegate functions in your view controller, add:

func scrollViewDidScroll(_ scrollView: UIScrollView) {
yourCollectionView.updateUIOnScrollViewDidScroll(scrollView)
}

EDIT

If you want to use your collection like an external library and you don’t want to call the updated function every time, you can implement a custom class that only conform to the UICollectionViewDelegate (if you want you can have a separated CustomDataSource class too that implement data source and delegate), for example:

class YourCollectionViewDelegate: NSObject, UICollectionViewDelegate {
// implement a callback for every function you need to manage in the view controller
var onSelectedItemAt: ((IndexPath) -> Void)?
func collectionView(_ collectionView: UICollectionView,
didSelectItemAt indexPath: IndexPath)
onSelectedItemAt?(indexPath)
}

func scrollViewDidScroll(_ scrollView: UIScrollView) {
guard let collectionView = scrollView as? YourCollectionViewClass else { fatalError(“your message”) }
// implement your ui update
}

Then in your view controller you just have to bind the delegate with your view controller:

class MyViewController: UIViewController {

//...
let customDelegate = YourCollectionViewDelegate()

override func viewDidLoad() {
super.viewDidLoad()
//...
myCollection.delegate = customDelegate
setupBindings()
}

private func setupBindings() {

customDelegate.onSelectedItemAt = { [weak self] indexPath in
//...
}
}

didDeselectItemAt For UIcollectionView is not called but didSelectItemAt is called?

I'm going to guess that your code is different from what you have shown us, and in that in your real code, you have not given the correct signature for didDeselect. Here's why. Look carefully at the code you have shown:

override func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
print("didSelectItemAt")

}

func collectionView(_ collectionView: UICollectionView, didDeselectItemAt indexPath: IndexPath) {
print("DESELECT")
}

Now ask yourself: Why did the compiler permit the second func to stand, even though you forgot to say override? I'm guessing it's because it is not an override. There is something wrong with the signature, so it's just a meaningless function that doesn't conform to UICollectionViewDelegate.

Try using code completion to re-enter this function. If all goes well, it will be an override and it will start working.


To illustrate more precisely: This compiles, but the second method will never be called:

class CV : UICollectionViewController {
override func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
print("didSelectItemAt")
}
func colectionView(_ collectionView: UICollectionView, didDeselectItemAt indexPath: IndexPath) {
print("DESELECT")
}
}

But this doesn't compile, because the signature is correct but we forgot override:

class CV : UICollectionViewController {
override func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
print("didSelectItemAt")
}
func collectionView(_ collectionView: UICollectionView, didDeselectItemAt indexPath: IndexPath) {
print("DESELECT")
}
}

But in that second one, if we do say override, it compiles and works.



Related Topics



Leave a reply



Submit