I've got a XIB named 'ImageViewController.xib" which contains a collection view. I've set up my desired collection view layout on this collection view inside the xib.
When trying to run my app I get the error message:
'UICollectionView must be initialized with a non-nil layout parameter'
I'm using this inside ImageViewController:
-(id) initWithImages:(NSArray *)imagesUrls
{
if (self = [super initWithCollectionViewLayout:self.collectionViewLayout]) {
self.imageUrls = [[NSArray alloc] initWithArray:imagesUrls];
}
[self.collectionView registerNib:[UINib nibWithNibName:#"ImageCell" bundle:nil] forCellWithReuseIdentifier:#"Cell"];
return self;
}
I just want to use the layout I have set up in the XIB and not make one programatically.
You can add the collectionViewLayout to the collectionView in the viewDidLoad.
Create your collectionViewLayout eg:
UICollectionViewFlowLayout * flowLayout = [[UICollectionViewFlowLayout alloc] init];
flowLayout.scrollDirection = UICollectionViewScrollDirectionHorizontal;
flowLayout.minimumLineSpacing = 5;
flowLayout.minimumInteritemSpacing = 5;
flowLayout.sectionInset = UIEdgeInsetsMake(5, 5, 5, 5);
Then we set it as the flow layout of the collectionView
_collectionView.collectionViewLayout = flowLayout;
I found this answer on a good tutorial which can be found here
Hopefully this helps
Try adding this in your view did Load method act its what I did to get rid of it
UICollectionViewFlowLayout* flowLayout = [[UICollectionViewFlowLayout alloc]init];
flowLayout.itemSize = CGSizeMake(100, 100);
[flowLayout setScrollDirection:UICollectionViewScrollDirectionHorizontal];
[self.collectionView registerClass:[UICollectionViewCell class] forCellWithReuseIdentifier:#"MyCell"];
this worked for me…you see what the error is telling you that the layout should not be nil, the Layout's frame is set relative to its superview, the layout is passed to the parent class during initialization, check if your CollectionViewLayout is "Null"
Related
I have a collection view wrap by UIView, the collection view has same bounds with wrapper view. And collection view data source will be changed, so the wrapper view bounds also be changed. I have implement the wrapper view intrinsicContentSize method with collectionView.collectionViewLayout.collectionViewContentSize, and the collection view layout is subclass of UICollectionViewFlowLayout, the cell of the UICollectionView has also implement method intrinsicContentSize, but the wrapper view did not update frame with collection view content size. collectionViewContentSize is always CGRectZero.
I have tried
[self.layout invalidateLayout];
[self.collectionView reloadData];
[self.collectionView layoutIfNeeded];
but did not work,
What should I do to update the wrapper view frame with collectionView.collectionViewLayout.collectionViewContentSize.
There is some code below:
ZXCollectionViewWrapperView *wrapperView = [[ZXCollectionViewWrapperView alloc] init];
[self.view addSubview:wrapperView];
[wrapperView mas_makeConstraints:^(MASConstraintMaker *make) {
make.center.equalTo(self.view);
}];
self.wrapperView = wrapperView;
/// wrapper view size
- (CGSize)intrinsicContentSize {
return self.collectionView.collectionViewLayout.collectionViewContentSize;
}
ZXCollectionViewAlignedLayout *layout = [[ZXCollectionViewAlignedLayout alloc] init];
self.layout = layout;
ZXCollectionView *collectionView = [[ZXCollectionView alloc] initWithFrame:CGRectZero collectionViewLayout:layout];
collectionView.dataSource = self;
collectionView.delegate = self;
collectionView.backgroundColor = [UIColor lightGrayColor];
[self addSubview:collectionView];
[collectionView mas_makeConstraints:^(MASConstraintMaker *make) {
make.edges.equalTo(self);
}];
self.collectionView = collectionView;
[self.collectionView zx_registerCellClass:[ZXCommendCell class]];
self.dataSource = dataSource;
[self.collectionView reloadData];
[self.collectionView layoutIfNeeded];
As you are using autolayout, you should create a height constraint for wrapper view. Then you can change the constant of that constraint to equal collection view content size, like this:
heightConstraint = make.height.equalTo(200) // initial height
then you can use KVO to observe collection view content size to change and set
heightConstraint.constant = collectionView.contentSize.height
you can refer to this for observing contentSize: observing contentSize (CGSize) with KVO in swift
I'm trying to implements this library without using storyBoard (first step for implementing this library) , because I'm creating my UIcollectionView programmatically.
- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view.
//self.view.backgroundColor = [UIColor whiteColor];
[self.view addSubview:self.collectionView];
[_collectionView registerNib:[UINib nibWithNibName:#"myCell" bundle:nil] forCellWithReuseIdentifier:#"cell3"];
[_collectionView setBackgroundColor:[UIColor colorWithRed:0.945 green:0.945 blue:0.945 alpha:1] ];
[_collectionView setTransform:CGAffineTransformMakeScale(-1, 1)];
RFQuiltLayout* layout = (id)[_collectionView collectionViewLayout];
layout.direction = UICollectionViewScrollDirectionVertical;
layout.blockPixels = CGSizeMake(100, 100);
}
- (UICollectionView *)collectionView {
if (!_collectionView) {
CGRect collectionViewFrame = self.view.bounds;
collectionViewFrame.size.height -= (self.navigationController.viewControllers.count > 1 ? 0 : (CGRectGetHeight(self.tabBarController.tabBar.bounds))) + 0;
// FMMosaicLayout *mosaicLayout = [[FMMosaicLayout alloc] init];
//// _collectionView = [[UICollectionView alloc] initWithFrame:collectionViewFrame collectionViewLayout:mosaicLayout];
// RFQuiltLayout* layout = (id)[_collectionView collectionViewLayout];
// layout.direction = UICollectionViewScrollDirectionVertical;
// layout.blockPixels = CGSizeMake(100, 100);
_collectionView = [[UICollectionView alloc] initWithFrame:collectionViewFrame collectionViewLayout:[[RFQuiltLayout alloc] init]];
_collectionView.delegate = self;
_collectionView.dataSource = self;
}
return _collectionView;
}
But this didn't worked and nothing is shown in my view (no error and empty view that's all) Also using debugger I've notified that the UICollectionView Method are never called
First of all, your collectionView method is not called because you are using _collectionView instead self.collectionView in your viewDidLoad method. You need to write self for every property to call their setter and getter methods.
Second, if you want to add custom layout without Storyboard of XIB, then you need to set it programmatically:
RFQuiltLayout* layout = [[RFQuiltLayout alloc] init];
layout.direction = UICollectionViewScrollDirectionVertical;
layout.blockPixels = CGSizeMake(100, 100);
self.collectionView.collectionViewLayout = layout;
All of my delegate are hooked up and called for a vertical layout object. In horizontal mode, for some reason the only delegate called is numberofcellsincollectionview (which returns correct number) - cellforitematindexpath isn't called unless I increase the size of the collectionview frame. when it is large enough cellforitematindexpath is called. This strange behavior only happens when the collectionview layout is in horizontal mode. In vertical mode not getting this behavior. (also this strange behavior only started in iOS7 - don't know if there is a connection)
horizontal layout code
-(UICollectionViewFlowLayout *)getFilmStripLayout
{
UICollectionViewFlowLayout *flowLayout = [[UICollectionViewFlowLayout alloc] init];
[flowLayout setScrollDirection:UICollectionViewScrollDirectionHorizontal];
[flowLayout setSectionInset:UIEdgeInsetsMake(0, 0, 0, 0)];
CGSize s = CGSizeMake(self.frame.size.height,self.frame.size.height);
[flowLayout setItemSize:s];
return flowLayout;
}
View controller containing view
-(UIThumbnailGalleryView *)gallery
{
if (_gallery == nil)
{
CGRect r = CGRectInset(self.filmStripRect, 0, -20); // started with inset 0,0 , increased the size and then the delegates are called.
_gallery = [[UIThumbnailGalleryView alloc] init2WithFrame:r]; // custom initializer testing layouts
[_gallery setBackgroundColor:[UIColor clearColor]];
[_gallery setBackgroundColor:[UIColor purpleColor]]; // setting colors in order to see the placement
_gallery.layer.borderColor = [UIColor orangeColor].CGColor;
_gallery.layer.borderWidth = 3;
_gallery.dataSource = self;
_gallery.delegate = self;
[_gallery setInToggleMode:YES];
}
return _gallery;
}
I am creating a UICollectionViewController programmatically. No, I don't want to use IB and Storyboards like every tutorial out there. I just want to use plain code.
Here is what I have in my viewDidLoad:
// UICollectionView
UICollectionViewFlowLayout *aFlowLayout = [[UICollectionViewFlowLayout alloc] init];
[aFlowLayout setItemSize:CGSizeMake(200, 140)];
[aFlowLayout setScrollDirection:UICollectionViewScrollDirectionVertical];
self.collectionView = [[UICollectionView alloc] initWithFrame:self.view.frame collectionViewLayout:aFlowLayout];
[self.collectionView setDelegate:self];
[self.collectionView setDataSource:self];
self.collectionView.backgroundColor = [UIColor clearColor];
[self.collectionView setAutoresizingMask:UIViewAutoresizingFlexibleHeight | UIViewAutoresizingFlexibleLeftMargin | UIViewAutoresizingFlexibleRightMargin | UIViewAutoresizingFlexibleWidth];
[self.collectionView registerClass:[PUCImageGridCell class] forCellWithReuseIdentifier:CollectionViewCellIdentifier];
I have implemented the required delegate methods and I still get this error:
Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: 'UICollectionView must be initialized with a non-nil layout parameter'
This is what I use to initialize a UICollectionViewController:
- (id)initWithCollectionViewLayout:(UICollectionViewLayout *)layout
You do not need to instantiate the collectionView the controller will do it for you. Set the frame after calling this or you can override and set the frame inside:
- (id)initWithCollectionViewLayout:(UICollectionViewLayout *)layout{
self = [super initWithCollectionViewLayout:layout];
if (self) {
// additional setup here if required.
}
return self;
}
I prefer to use the autolayout constraints.
I'm making a horizontal picker by using a UICollectionView. It's simple enough: A UIView with a UICollectionView created programmatically, using UICollectionViewFlowLayout with one section, scrolling set to horizontal. It appears onscreen, complete with the correct data in the correct cells. But it doesn't scroll---in fact it doesn't respond to user interaction at all.
Here's the initializer for the view:
- (id)initWithFrame:(CGRect)frame andItemData:(NSArray *)itemData
{
self = [super initWithFrame:frame];
if (self) {
_itemData = itemData;
UICollectionViewFlowLayout *flowLayout = [[UICollectionViewFlowLayout alloc] init];
[flowLayout setScrollDirection:UICollectionViewScrollDirectionHorizontal];
[flowLayout setItemSize:CGSizeMake(kCellWidth, kCellHeight)];
[flowLayout setMinimumInteritemSpacing:0.f];
[flowLayout setMinimumLineSpacing:0.f];
_collectionView = [[UICollectionView alloc] initWithFrame:[self frame] collectionViewLayout:flowLayout];
[_collectionView setDataSource:self];
[_collectionView setDelegate:self];
[_collectionView setBounces:NO];
[_collectionView registerClass:[UICollectionViewCell class] forCellWithReuseIdentifier:#"HorizontalPickerCell"];
[self addSubview:_collectionView];
}
return self;
}
I tried programmatically setting UserInteractionEnabled to YES, but that didn't make any difference (nor should it have, since UserInteractionEnabled is set to YES by default). FWIW, the collection view uses standard UICollectionViewCells with UILabels added to their contentViews as subviews.
Any thought as to why this isn't scrolling? Any and all help much appreciated.
Ok, this turned out to be both dumb on my part and easy to fix. I set the frame of the collection view to its parent view's frame rather than its bounds. This caused all sorts of autolayout issues and resulted in touch events simply not registering. All fixed now.