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
Why in Swift We Cannot Adopt a Protocol Without Inheritance a Class from Nsobject
Structs That Refer to Each Other in Swift 3
Swift, Auto Resize Custom Table View Cells
Why Should Not Directly Extend Uiview or Uiviewcontroller
Reading Currently Playing Track in MACos Using Scriptingbridge Not Working
Make a Uibarbuttonitem Disappear Using Swift iOS
Difference Between String Interpolation and String Initializer in Swift
In Swift, What Does It Mean for Protocol to Inherit from Class Keyword
App Delegate Accessing Environment Object
Using Stringbyreplacingcharactersinrange in Swift
Difference Between Associated and Raw Values in Swift Enumerations
Sprite Kit Physicsbody.Resting Behavior
How to Detect Absent Network Connection When Setting Firestore Document
"Cannot Assign Value of Type 'String' to Type 'Anyobject'", Swift 3, Xcode 8 Beta 6
Checking If an Array of Custom Objects Contain a Specific Custom Object