Alright so lets say I have UICollection with 20 cells That scrolls horizontally with paging enabled and can fit 9 cells on each page, when I make it 10 cells instead of creating a second page it moves just enough to fit the 10th cell on the page. I want it to display the 10th cell on its own page when I scroll over.
Also i have tried changing the collectionview.contentsize but for some reason it stays the same no matter what i do.
Here is my code -
- (CGSize)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout*)collectionViewLayout sizeForItemAtIndexPath:(NSIndexPath *)indexPath
{
return CGSizeMake(82, 119);
}
- (UIEdgeInsets)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout*)collectionViewLayout insetForSectionAtIndex:(NSInteger)section {
return UIEdgeInsetsMake(20, 10, 50, 10);
}
- (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath
{
customCell *cell= (customCell*)[collectionView dequeueReusableCellWithReuseIdentifier:#"cellIdentifier" forIndexPath:indexPath];
return (UICollectionViewCell*)cell;
}
-(NSInteger)numberOfSectionsInCollectionView:(UICollectionView *)collectionView{
return 1;
}
-(NSInteger)collectionView:(UICollectionView *)collectionView numberOfItemsInSection:(NSInteger)section{
return 20;
}
- (void)viewDidLoad {
UICollectionViewFlowLayout *layout=[[UICollectionViewFlowLayout alloc] init];
_collectionView=[[UICollectionView alloc] initWithFrame:self.view.frame collectionViewLayout:layout];
[_collectionView setDataSource:self];
[_collectionView setDelegate:self];
[_collectionView registerClass:[UICollectionViewCell class] forCellWithReuseIdentifier:#"cellIdentifier"];
[_collectionView setBackgroundColor:[UIColor lightGrayColor]];
[layout setScrollDirection:UICollectionViewScrollDirectionHorizontal];
_collectionView.pagingEnabled = YES;
layout.minimumInteritemSpacing = 15;
layout.minimumLineSpacing = 25;
[_collectionView setContentInset:UIEdgeInsetsMake(65, 0, 0, 0)];
_collectionView.allowsMultipleSelection = YES;
[self.view addSubview:_collectionView];
[super viewDidLoad];
// Do any additional setup after loading the view.
}
You can't force the collection view to completely scroll to a new page like that unfortunately.
Instead, just calculate the number of cells required to fill out the page and add empty ones to the end of your dataset.
For example, if you've got 19 items in your NSArray of data, add another 8 to bring the total up to 27.
In your collectionView:numberOfItemsInSection: delegate, do something like:
return (dataArray.count % 9 == 0) ? dataArray.count : ((dataArray.count/9|0)+1)*9;
// 17 returns 18
// 19 returns 27
Just make sure you perform a contingency operation in cellForItemAtIndexPath to display a blank cell (since your dataset won't actually contain data for that item).
Related
For some reason, when I'm on the first page of UICollectionView,
it shows the images from the second page.
And I also noticed that the page isn't centered....
I manually set the
pageControl.numberOfPages = 3
So I have three pages of images.
And each page displays 8 items (well...ideally).
This is in ViewDidLoad:
UICollectionViewFlowLayout *layout=[[UICollectionViewFlowLayout alloc] init];
[layout setSectionInset:UIEdgeInsetsMake(10, 10, 15, 10)];
[layout setScrollDirection:UICollectionViewScrollDirectionHorizontal];
[self.collectionView setCollectionViewLayout:layout];
self.collectionView = [[UICollectionView alloc] initWithFrame:keyboardRect collectionViewLayout:layout];
self.collectionView.dataSource = self;
self.collectionView.delegate = self;
self.collectionView.pagingEnabled = true;
self.collectionView.alwaysBounceHorizontal = true;
self.collectionView.contentSize = CGSizeMake(keyboardRect.size.width , keyboardRect.size.height);
self.collectionView.showsHorizontalScrollIndicator = false;
UINib *cellNib = [UINib nibWithNibName:#"TopCell" bundle:nil];
[self.collectionView registerNib:cellNib forCellWithReuseIdentifier:#"cellIdentifier"];
[self.collectionView registerClass:[TopCollectionViewCell class] forCellWithReuseIdentifier:#"cellIdentifier"];
[self.collectionView setBackgroundColor:[UIColor redColor]];
[self.view addSubview:self.collectionView];
When I tried to increase left and right inset from
[layout setSectionInset:UIEdgeInsetsMake(10, 10, 15, 10)];
It just made things worse. It'd only look okay on the first page,
but then the second and third pages would look off.
And here are some of my code:
-(NSInteger)collectionView:(UICollectionView *)collectionView numberOfItemsInSection:(NSInteger)section {
return [self.Images count];
}
-(CGSize)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout *)collectionViewLayout sizeForItemAtIndexPath:(NSIndexPath *)indexPath {
return CGSizeMake(70, 70);
}
-(NSInteger)numberOfSectionsInCollectionView:(UICollectionView* )collectionView {
return 3;
}
Thank you in advance!
If you want to show only one section images in each page, then you have to modify
-(CGSize)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout *)collectionViewLayout sizeForItemAtIndexPath:(NSIndexPath *)indexPath method.
You have to return a more generic size.
CGSize returnSize = CGSizeMake(screenWidth / 2 - insets, screenWidth / 2 - insets)
Here inset represents the interItemSpacing for each item. screenWidth is collectionView width.
If you want use the horizontal style of collectionView,you need to custom layout.
Here are some sample code you can use, and I have uploaded custom layout code on github.
FCEmoticonViewLayout *layout = [[FCEmoticonViewLayout alloc]init];
layout.itemSize = CGSizeMake(itemWidht, itemWidht);
layout.itemSpacing = 15;
layout.lineSpacing = 15;
layout.numberOfColumn = 5;
layout.numberOfRow = 2;
self.collectionView.collectionViewLayout = layout;
https://gist.github.com/Heisenbean/a0de38c1379a9d6a83f09ba6cafcb03c
Hi I am very new for Ios and in my project I am using UICollectionView ok that's fine.
But here my main requirement is that I want to load the UICollectionView cells dynamically when we are scrolling the collectionView.
I mean when we launch the app then first "5" records need to load and when we are scrolling for the first time next "5" records need to load and when we scrolling for the second time the next "5" records need to be displayed and in that way all records need to load.
Please help me.
How can I do this?
my code:-
#import "ViewController.h"
#interface ViewController ()
{
UICollectionView * _collectionView;
}
#end
#implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
UICollectionViewFlowLayout *layout=[[UICollectionViewFlowLayout alloc] init];
_collectionView = [[UICollectionView alloc]initWithFrame:CGRectMake(0, 0, 320, 480) collectionViewLayout:layout];
[_collectionView setDataSource:self];
[_collectionView setDelegate:self];
[_collectionView registerClass:[UICollectionViewCell class] forCellWithReuseIdentifier:#"cellIdentifier"];
[_collectionView setBackgroundColor:[UIColor clearColor]];
[self.view addSubview:_collectionView];
UIView *refreshView = [[UIView alloc] initWithFrame:CGRectMake(0, _collectionView.frame.size.height - 50, 0, 0)];
[_collectionView addSubview:refreshView];
UIRefreshControl *refreshControl = [UIRefreshControl new];
refreshControl.tintColor = [UIColor redColor];
[refreshControl addTarget:self action:#selector(viewDidBeginRefreshing:) forControlEvents:UIControlEventValueChanged];
[refreshView addSubview:refreshControl];
}
- (NSInteger)collectionView:(UICollectionView *)collectionView numberOfItemsInSection:(NSInteger)section{
return 5;
}
- (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath{
UICollectionViewCell *cell=[collectionView dequeueReusableCellWithReuseIdentifier:#"cellIdentifier" forIndexPath:indexPath];
for (id subview in cell.contentView.subviews) {
if ([subview isKindOfClass:[UIImageView class]]) {
[subview removeFromSuperview];
} else if ([subview isKindOfClass:[UILabel class]]) {
[subview removeFromSuperview];
}
}
cell.backgroundColor = [UIColor lightGrayColor];
return cell;
}
- (CGSize)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout*)collectionViewLayout sizeForItemAtIndexPath:(NSIndexPath *)indexPath{
return CGSizeMake(70, 70);
}
- (UIEdgeInsets)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout*)collectionViewLayout insetForSectionAtIndex:(NSInteger)section{
UIEdgeInsets insets=UIEdgeInsetsMake(10, 10, 10, 10);
return insets;
}
- (CGFloat)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout*)collectionViewLayout minimumLineSpacingForSectionAtIndex:(NSInteger)section {
return 30.0;
}
Solution: You can add infinite scrolling to your existing UICollectionView use the following open source library to archive your requirement.
UIScrollView-InfiniteScroll
Solution 1: If you want to do infinite scrolling in a manner more like a desktop web app, you should implement the UIScrollViewDelegate protocol (or UICollectionViewDelegate, which is a superset) and listen for the scrollViewDidScroll: callback.
Within that callback, iterate through the UICollectionView's indexPathsForVisibleItems and check to see if any of the index paths map to the 'last' item in your collection, which indicates the user has scrolled to the end.
At that point, call your logic to load more stuff.
Solution 2:
In table view, you should load more data in willDisplayCell() method. With collections, there is no such a counterpart. But, you can do like this. Hope, it helps.
(void)collectionView:(UICollectionView *)collectionView willDisplayCell:(UICollectionViewCell *)cell forItemAtIndexPath:(NSIndexPath *)indexPath
{
// Other code here ...
if (indexPath.item == [self.data count] - 1) {
[self loadMoreData];
}
}
May be it will help you.
I am using third party UiCollection View KRLCollectionViewGridLayout.
In this I have the following issue attached in screen shot.
See the above screen shot. There is an extra space in collectionview cell.
My Question is how to remove these extra space in collection cell and also how to add separator between two cell?
Here is my Code:
- (KRLCollectionViewGridLayout *)layout
{
return (id)self.collectionView.collectionViewLayout;
}
- (IBAction)changeColumnsTapped:(id)sender {
[[[UIActionSheet alloc] initWithTitle:#"Choose how many columns"
delegate:self
cancelButtonTitle:nil
destructiveButtonTitle:nil
otherButtonTitles:#"1",#"2", nil]
showInView:self.view];
}
- (void)actionSheet:(UIActionSheet *)actionSheet clickedButtonAtIndex:(NSInteger)buttonIndex
{
self.layout.numberOfItemsPerLine = [[actionSheet buttonTitleAtIndex:buttonIndex] integerValue];
}
- (void)viewDidLoad
{
[super viewDidLoad];
UISearchBar *searchBar = [[UISearchBar alloc]initWithFrame:CGRectMake(0, -44, self.view.frame.size.width, 44.0)];
[self.collectionView addSubview:searchBar];
[self.collectionView setContentInset:UIEdgeInsetsMake(44, 0, 0, 0)];
self.layout.numberOfItemsPerLine = 1;
self.layout.aspectRatio = 1;
self.layout.sectionInset = UIEdgeInsetsMake(10, 10, 10, 10);
self.layout.interitemSpacing = 10;
self.layout.lineSpacing = 10;
// Uncomment the following line to preserve selection between presentations
// self.clearsSelectionOnViewWillAppear = NO;
// Register cell classes
[self.collectionView registerClass:[UICollectionViewCell class] forCellWithReuseIdentifier:reuseIdentifier];
//recipePhotos = [NSMutableArray arrayWithObjects:#"image1.png",#"image2.png",#"image3.png", nil];
recipePhotos = [NSMutableArray arrayWithObjects:#"image1.png", nil];
}
- (void)didReceiveMemoryWarning {
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
- (NSInteger)numberOfSectionsInCollectionView:(UICollectionView *)collectionView
{
return 1;
}
- (NSInteger)collectionView:(UICollectionView *)collectionView numberOfItemsInSection:(NSInteger)section
{
return [recipePhotos count];
}
- (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath
{
UICollectionViewCell *cell = [collectionView dequeueReusableCellWithReuseIdentifier:#"Cell1" forIndexPath:indexPath];
//cell.contentView.backgroundColor = [UIColor blueColor];
UIImageView *recipeImageView = (UIImageView *)[cell viewWithTag:100];
recipeImageView.image = [UIImage imageNamed:[recipePhotos objectAtIndex:indexPath.row]];
cell.layer.borderWidth = 0.5;
return cell;
}
I'm the author of this layout. As it stands now, it looks like you're using the default value of the layout's aspectRatio property of 1/1 which is what is in charge of sizing the cells. Unfortunately this layout does not yet support dynamically-sized cells, but I may do so in the future. If you know how high your cells are intended to be relative to their width, you can set the aspect ratio accordingly. an aspect ratio of 2 would mean it's twice as long as it is tall, and an aspect ratio of 0.5 would mean it's 1/2 as long as it is tall. You probably want some number greater than 1 for your ratio to decrease the spacing.
If that doesn't give you the effect you want, you may need to switch to UICollectionViewFlowLayout instead which gives you precise control over the size of cells.
Try This. Check This Link Cell spacing in UICollectionView
- (CGFloat)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout*)collectionViewLayout minimumInteritemSpacingForSectionAtIndex:(NSInteger)section {
return 2.0;
}
- (CGFloat)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout*)collectionViewLayout minimumLineSpacingForSectionAtIndex:(NSInteger)section {
return 2.0;
}
// Layout: Set Edges
- (UIEdgeInsets)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout*)collectionViewLayout insetForSectionAtIndex:(NSInteger)section {
// return UIEdgeInsetsMake(0,8,0,8); // top, left, bottom, right
return UIEdgeInsetsMake(0,0,0,0); // top, left, bottom, right
}
Add UICollectionViewDelegateFlowLayout delegate in you interface
and ipmplement
-(CGSize)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout *)collectionViewLayout sizeForItemAtIndexPath:(NSIndexPath *)indexPath {
return IPAD ? CGSizeMake(75, 75) : CGSizeMake(55, 55);
}
And change size as per your requirement.
I am using a UICollectionView to produce a grid of cells say total of 10 i.e. 0-9.
Now, I want to insert a new cell in the grid on click of one of the cells.
so I have added the following line of code [_collectionView insertItemsAtIndexPaths:#[[NSIndexPath indexPathForItem:10 inSection:0]]]; inside the function didSelectItemAtIndexPath.
So now, if I set indexPathForItem: as 10 (i.e. insert at last) then I get 'Assertion failure' error on this line. If I set `indexPathForItem:' anything between 0-9 then I get 'EXC_BAD_ACCESS...' error on this line.
This is my complete code implementing UICollectionView:
- (void)loadView
{
self.view = [[UIView alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
UICollectionViewFlowLayout *layout=[[UICollectionViewFlowLayout alloc] init];
_collectionView=[[UICollectionView alloc] initWithFrame:CGRectMake(0, 97.5, self.view.frame.size.width, self.view.frame.size.height-67.5) collectionViewLayout:layout];
[_collectionView setDataSource:self];
[_collectionView setDelegate:self];
[_collectionView registerClass:[UICollectionViewCell class] forCellWithReuseIdentifier:#"cellIdentifier"];
[_collectionView setBackgroundColor:[UIColor whiteColor]];
[self.view addSubview:_collectionView];
}
- (NSInteger)collectionView:(UICollectionView *)collectionView numberOfItemsInSection: (NSInteger)section
{
return 35;
}
- (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath
{
UICollectionViewCell *cell=[collectionView dequeueReusableCellWithReuseIdentifier:#"cellIdentifier" forIndexPath:indexPath];
cell.layer.borderWidth=.5f;
cell.layer.borderColor=[UIColor blackColor].CGColor;
if(indexPath.item<31)
{
_dayNumber = [[UILabel alloc] initWithFrame:CGRectMake(30, 30, 15, 15)];
_dayNumber.font = [UIFont systemFontOfSize:12];
_dayNumber.text = [NSString stringWithFormat:#"%ld",(indexPath.item + 1)];
[cell addSubview:_dayNumber];
}
return cell;
}
- (CGSize)collectionView:(UICollectionView *)collectionView layout: (UICollectionViewLayout*)collectionViewLayout sizeForItemAtIndexPath:(NSIndexPath *)indexPath
{
return CGSizeMake(self.view.frame.size.width/7, self.view.frame.size.width/7);
}
- (CGFloat)collectionView:(UICollectionView *)collectionView layout: (UICollectionViewLayout*)collectionViewLayout minimumInteritemSpacingForSectionAtIndex: (NSInteger)section
{
return 0.0;
}
- (CGFloat)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout*)collectionViewLayout minimumLineSpacingForSectionAtIndex:(NSInteger)section
{
return 0.0;
}
// Layout: Set Edges
- (UIEdgeInsets)collectionView:
(UICollectionView *)collectionView layout: (UICollectionViewLayout*)collectionViewLayout insetForSectionAtIndex:(NSInteger)section
{
return UIEdgeInsetsMake(0,0,0,0); // top, left, bottom, right
}
- (void)collectionView:(UICollectionView *)collectionView didSelectItemAtIndexPath: (NSIndexPath *)indexPath
{
[_collectionView insertItemsAtIndexPaths:#[[NSIndexPath indexPathForItem:0 inSection:0]]];
}
Any help?
Well,
first let's consider this method,
- (NSInteger)collectionView:(UICollectionView *)collectionView numberOfItemsInSection: (NSInteger)section
{
return 35; // returning constant value means that you can't add or remove cells later
}
so let me change this to
- (NSInteger)collectionView:(UICollectionView *)collectionView numberOfItemsInSection: (NSInteger)section
{
return self.itemsCount;
}
declare itemsCount property in your class interface, like this
#interface YourClass ()
#property (nonatomic) NSInteger itemsCount;
#end
initialize it in loadView or init method,
_itemsCount = 35; // or whatever you want, initial count
now we can insert/delete items, right ? when we call insertItemAtIndexPaths all we have to do is updating actual data before that call, (for example self.itemsCount++, [self.myItems addObject:newItem] )
here is changes in your code
- (void)collectionView:(UICollectionView *)collectionView didSelectItemAtIndexPath:(NSIndexPath *)indexPath
{
self.itemsCount++; // updating data
[_collectionView insertItemsAtIndexPaths:#[[NSIndexPath indexPathForItem:0 inSection:0]]];
}
One last important thing, in cellForItemAtIndexPath don't alloc init any kind of view and add as subview on cell, this code every time creates UILabels on cell, if you want custom view on cell (like an imageview, button, etc ..) you should subclass UICollectionViewCell and create this stuff in it's init method, here is how it will look like
- (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath
{
YourCell *cell=[collectionView dequeueReusableCellWithReuseIdentifier:#"cellIdentifier" forIndexPath:indexPath];
cell.layer.borderWidth = 0.5;
cell.layer.borderColor = [UIColor blackColor].CGColor;
cell.dayNumber.font = [UIFont systemFontOfSize:12];
cell.dayNumber.text = [NSString stringWithFormat:#"%d",(indexPath.row + 1)];
return cell;
}
assuming you also changed this line,
[_collectionView registerClass:[YourCell class] forCellWithReuseIdentifier:#"cellIdentifier"];
note that YourCell is a subclass of UICollectionViewCell and has property dayNumber
Apple has a great guide about collection views. I recommend to read it.
Good luck.
I have a Collection View and has custom cells with images and labels in there. I have set my collection view as follows -
UICollectionViewFlowLayout *flowLayout = [[UICollectionViewFlowLayout alloc] init];
[flowLayout setScrollDirection:UICollectionViewScrollDirectionVertical];
flowLayout.minimumLineSpacing = 150.0f;
flowLayout.minimumInteritemSpacing = 104.0f;
flowLayout.sectionInset = UIEdgeInsetsMake(20, 20, 100, 120);
_archiveCollectionView = [[UICollectionView alloc] initWithFrame:self.view.bounds collectionViewLayout:flowLayout];
_archiveCollectionView.frame = CGRectMake(30, 218, _archiveCollectionView.frame.size.width - 60, _archiveCollectionView.frame.size.height - 350);
_archiveCollectionView.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight;
_archiveCollectionView.backgroundColor = [UIColor clearColor];
_archiveCollectionView.delegate = self;
_archiveCollectionView.dataSource = self;
[self.archiveCollectionView registerNib:[UINib nibWithNibName:#"FullArchiveEditionCell" bundle:nil] forCellWithReuseIdentifier:#"MyCell"];
[_archiveCollectionView reloadData];
[self.view addSubview:_archiveCollectionView];
I have also set the following methods:
-(NSInteger)collectionView:(UICollectionView *)collectionView numberOfItemsInSection:(NSInteger)section {
return _chosenCategoryArray.count;
}
- (NSInteger)numberOfSectionsInCollectionView:(UICollectionView *)collectionView {
return 1;
}
-(void)collectionView:(UICollectionView *)collectionView didSelectItemAtIndexPath:(NSIndexPath *)indexPath {
[self addEditionsChildView];
}
-(BOOL)collectionView:(UICollectionView *)collectionView shouldSelectItemAtIndexPath:(NSIndexPath *)indexPath {
return YES;
}
However, my didSelectItemAtIndexPath never gets called when I select a cell. Any help please?
I had a similar problem and it turned out I was using the same cell reuse identifier in two different collection views
In your header file have you implemented UICollectionViewDelegate as like below,
#interface HAViewController : UIViewController <UICollectionViewDataSource, UICollectionViewDelegate>
I have the same problem. And I solved by using storyboard to locate the collection cell in the collection view controller. Then tick User InterAction Enabled. I think using code to set in the UICollectionViewCell would also work. Hope it would help.
Try with changing sequence as given below
[_archiveCollectionView reloadData];
[self.view addSubview:_archiveCollectionView];
to
[self.view addSubview:_archiveCollectionView];
[_archiveCollectionView reloadData];
Implement the below delegate method.
- (BOOL)collectionView:(UICollectionView *)collectionView shouldDeselectItemAtIndexPath:(NSIndexPath *)indexPath{
return YES;
}
And implement your
- (void)collectionView:(UICollectionView *)collectionView didDeselectItemAtIndexPath:(NSIndexPath *)indexPath {
//your selection management code
}
and
- (void)collectionView:(UICollectionView *)collectionView didDeselectItemAtIndexPath:(NSIndexPath *)indexPath{
//deselection handling code
}