I have a UICollectionView with a supplementary view -- in essence a header for the collection. Whenever I add a gesture recognizer to a UILabel within the headerView.xib using the interface builder, the app crashes giving me
*** Terminating app due to uncaught exception 'NSInternalInconsistencyException', reason: 'invalid nib registered for identifier (MY_HEADER) - nib must contain exactly one top level object which must be a UICollectionReusableView instance'
What is preventing me from adding a gesture recognizer to a UILabel within a supplementary view of a UICollectionView?
In the viewDidLoad () method, we invoke addGestureRecognizer (_:) on imageView, passing in the tap gesture recognizer, to add the tap gesture recognizer to imageView. Let's build and run the application to make sure the image view still responds to taps. Tap the image view and press Command + Shift + Y to inspect the output in the console.
The UICollectionViewController class provides a default gesture recognizer that you can use to rearrange items in its managed collection view. To install this gesture recognizer, set the installsStandardGestureForInteractiveMovement property of the collection view controller to true.
I always add gesture recognizers in code, but that is a personal choice. Let's start with Interface Builder. Open Main.storyboard and drag a tap gesture recognizer from the Object Library and drop it onto the image view we added earlier. The tap gesture recognizer appears in the Document Outline on the left.
By implementing the method, you provide a supplementary view to display in the collection view. First, download the header/footer background images and add them into the Xcode project. Go back to Storyboard. Select “Collection View” of the Collection View controller.
I add gesture recognizer when the supplementary view has been loaded from nib.
class MySuppleMentaryView: UICollectionReusableView
{
@IBOutlet var label: UILabel!
weak var delegate: MySuppleMentaryViewDelegate!
override func awakeFromNib() {
super.awakeFromNib()
// NOTE: UILabel MUST enable user interaction to receive touch events.
// label.isUserInteractionEnabled = true
let tap = UITapGestureRecognizer(target: self, action: #selector(onClickLabel))
tap.delaysTouchesBegan = true
tap.numberOfTapsRequired = 1
self.label.addGestureRecognizer(tap)
}
@objc func onClickLabel() {
self.delegate.didOnLabel(cell: self)
}
}
protocol MySuppleMentaryViewDelegate: NSObjectProtocol {
func didOnLabel(cell: DCScheduleHourLabel)
}
// Configure supplementary cell
func collectionView(_ collectionView: UICollectionView, viewForSupplementaryElementOfKind kind: String, at indexPath: IndexPath) -> UICollectionReusableView {
if (kind == UICollectionElementKindSectionHeader) {
// NOTE: The cell might be reused.
// If gesture recognizer is added HERE,
// then maybe multiple gesture recognizers are added when reusing the cell.
let cell = collectionView.dequeueReusableSupplementaryView(ofKind: kind, withReuseIdentifier: DCScheduleDummyBlock.Identifier, for: indexPath) as! MySuppleMentaryView
// configure cell
cell.delegate = self
return cell
}
return UICollectionReusableView()
}
So it looks like you cannot use the interface builder to add a gesture recognizer to a supplementary view of a UICollectionView.
I believe this is because when the .xib's are loaded, the UICollectionView must appear as one thing to the superview -- and when you add the gesture recognizer to that UICollectionView you end up with two things at the superview level, which both correspond to the UICollectionView.
You can however implement your gesture recognizer programmatically using the definition of your supplementary view inside of the UICollectionViewReusableView Protocol. (The if is being used to distinguish between a header supplementary view and an footer supplementary view later in the code)
if (kind == UICollectionElementKindSectionHeader) {
MyHeaderView *headerView = [collectionView dequeueReusableSupplementaryViewOfKind:UICollectionElementKindSectionHeader withReuseIdentifier:@"MY_HEADER" forIndexPath:indexPath];
// call headerView methods (to put things into the header's UI objects for example)
[headerView ...];
[headerView ...];
[headerView ...];
// add gesture recognition for tapping on a UIlabel within the header (UICollectionView supplementary view)
UITapGestureRecognizer *bioTap = [[UITapGestureRecognizer alloc] initWithTarget:headerView action:@selector(handleUILabelTap:)];
// make your gesture recognizer priority
bioTap.delaysTouchesBegan = YES;
bioTap.numberOfTapsRequired = 1;
[headerView.UILabelName addGestureRecognizer:UILabelTap];
reusableview = headerView;
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With