I am fiddling with the new UICollectionView and the UICollectionViewLayout classes. I have created a custom layout, subclassing UICollectionViewFlowLayout.
My cell sizes are changing dynamically and I set the item sizes using the delegate method below
- (CGSize)collectionView:(UICollectionView *)collectionView
layout:(UICollectionViewLayout*)collectionViewLayout
sizeForItemAtIndexPath:(NSIndexPath *)indexPath {
NSLog(@"SETTING SIZE FOR ITEM AT INDEX %d", indexPath.row);
return CGSizeMake(80, 80);
}
Now, under the prepareLayout method of my custom UICollectionViewFlowLayout class, I need to access these size variables so that I can make calculations how to place them and cache them for layoutAttributesForItemAtIndexPath.
However, I can't seem to find any property under UICollectionView or UICollectionViewFlowLayout to reach the custom item sizes I set in the delegate method.
Found it myself.
Implement the custom class like without omitting UICollectionViewDelegateFlowLayout
@interface SECollectionViewCustomLayout : UICollectionViewFlowLayout
<UICollectionViewDelegateFlowLayout>
and then you can call
CGSize size = [self collectionView:self.collectionView
layout:self
sizeForItemAtIndexPath:indexPath];
Looking at the various UICollectionView...
header files, and watching the WWDC 2012 Session 219 - Advanced Collection Views and Building Custom Layouts video (from about 6:50 onwards), it seems the extensible delegate pattern takes advantage of dynamic typing to ensure the layout can properly access its extended delegate methods.
UI(Collection)ViewController
that manages the collection view) should declare itself to support this custom protocol.
UICollectionViewFlowLayout
or subclass thereof, this just means declaring conformance to UICollectionViewDelegateFlowLayout
..m
file if you'd rather not #import
the layout header into the delegate's interface.collectionView
property, and cast the delegate to an object conforming to the required protocol to convince the compiler.respondsToSelector:
as usual prior to calling optional delegate methods. In fact, if you like, there's no harm in doing this for all methods, as the typecasting means there is no runtime guarantee the delegate will even implement the required methods.So if you implement a custom layout that requires a delegate for some of its information, your header might look something like this:
@protocol CollectionViewDelegateCustomLayout <UICollectionViewDelegate>
- (BOOL)collectionView:(UICollectionView *)collectionView
layout:(UICollectionViewLayout *)layout
shouldDoSomethingMindblowingAtIndexPath:(NSIndexPath *)indexPath;
@end
@interface CustomLayout : UICollectionViewLayout
// ...
@end
Your delegate declares conformance (I've done so in the implementation file here):
#import "CustomLayout.h"
@interface MyCollectionViewController () <CollectionViewDelegateCustomLayout>
@end
@implementation
// ...
- (BOOL)collectionView:(UICollectionView *)collectionView
layout:(UICollectionViewLayout *)layout
shouldDoSomethingMindblowingAtIndexPath:(NSIndexPath *)indexPath
{
return [self canDoSomethingMindblowing];
}
// ...
@end
And in your layout's implementation, you access the method like this:
BOOL blowMind;
if ([self.collectionView.delegate respondsToSelector:@selecor(collectionView:layout:shouldDoSomethingMindblowingAtIndexPath:)]) {
blowMind = [(id<CollectionViewDelegateCustomLayout>)self.collectionView.delegate collectionView:self.collectionView
layout:self
shouldDoSomethingMindblowingAtIndexPath:indexPath];
} else {
// Perhaps the layout also has a property for this, if the delegate
// doesn't support dynamic layout properties...?
// blowMind = self.blowMind;
}
Note that it's safe to typecast here, as we're checking the delegate responds to that method beforehand anyway.
It's only speculation, but I suspect it is how Apple manages the UICollectionViewDelegateFlowLayout
protocol.
delegate
property on the flow layout, so calls must go via the collection view's delegate.UICollectionViewController
does not publicly conform to extended flow layout delegate (and I doubt it does so in another private header).UICollectionView
's delegate
property only declares conformance to the 'base' UICollectionViewDelegate
protocol. Again, I doubt there is a private subclass/category of UICollectionView
in use by the flow layout to prevent the need for typecasting. To add further weight to this point, Apple discourages subclassing UICollectionView
at all in the docs (Collection View Programming Guide for iOS: Creating Custom Layouts):Avoid subclassing UICollectionView. The collection view has little or no appearance of its own. Instead, it pulls all of its views from your data source object and all of the layout-related information from the layout object.
So there we go. Not complicated, but worth knowing how to do it paradigm-friendly way.
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