I'm very new to UICollectionViews. I'm making a universal app. What I want is that on the iPad there are 2 cells on each row. But on the iPhone there is only one cell on each row. I was able to get the iPad version set correctly. But I can't get my head around the iPhone settings.
Here are the settings so far. And has you can see on my storyboard it looks oké. But when I run it I see that there are still two cells on each row.
Can someone help me with this ?
Kind regards
- (void)viewDidLoad
{
[super viewDidLoad];
[self.collectionView registerClass:[CVCell class] forCellWithReuseIdentifier:#"cvCell"];
// Configure layout
UICollectionViewFlowLayout *flowLayout = [[UICollectionViewFlowLayout alloc] init];
[flowLayout setItemSize:CGSizeMake(100, 100)];
[flowLayout setScrollDirection:UICollectionViewScrollDirectionHorizontal];
[self.collectionView setCollectionViewLayout:flowLayout];
}
-(void)viewWillAppear:(BOOL)animated {
[super viewWillAppear:animated];
deviceModel = (NSString*)[UIDevice currentDevice].model;
NSLog(#"device is = %#",deviceModel);
}
-(NSInteger)numberOfSectionsInCollectionView:(UICollectionView *)collectionView {
if ([deviceModel isEqualToString:#"iPhone Simulator"]) {
return 1;
}else
{
return 2;
}
}
-(NSInteger)collectionView:(UICollectionView *)collectionView numberOfItemsInSection:(NSInteger)section {
return 3;
}
-(UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath {
// Setup cell identifier
static NSString *cellIdentifier = #"cvCell";
/* Uncomment this block to use subclass-based cells */
CVCell *cell = (CVCell *)[collectionView dequeueReusableCellWithReuseIdentifier:cellIdentifier forIndexPath:indexPath];
if (indexPath.section == 0) {
cell.backgroundColor = [UIColor redColor];
}
if (indexPath.section == 1) {
cell.backgroundColor = [UIColor blueColor];
}
cell.titleLabel.text = [NSString stringWithFormat:#"item %ld",(long)indexPath.section];
// Return the cell
return cell;
}
Check this code which will give you one item in iPhone cell and two item in iPad..
Related
in one of my application i have implemented dashboard screen with collection view and when user clicks on collection view cell's it is not interacting this is happening to only iPhone12 pro max users
currently i don't have that real time device to test but i have tested in iPhone12 pro max simulator and its working fine
can you please suggest what was the cause or any suggestions?
thanks in advance
- (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath
{
if (indexPath.section == 0)
{
customClassCollectionViewCellOne *cell = [[customClassCollectionViewCellOne alloc]initWithFrame:CGRectMake(0, 0, 0, 0)];
cell = (customClassCollectionViewCellOne *)[collectionView dequeueReusableCellWithReuseIdentifier:#"accountBalance_main_collectionview" forIndexPath:indexPath];
cell.balanceArray = newbalanceArray;
cell.delegate = self;
[cell.collectionView reloadData];
return cell;
}
else if (indexPath.section == 1)
{
customClassCollectionViewCellTwo *cell = [[customClassCollectionViewCellTwo alloc]initWithFrame:CGRectMake(0, 0, 0, 0)];
cell = (customClassCollectionViewCellTwo *)[collectionView dequeueReusableCellWithReuseIdentifier:#"QuickActions_main_collectionview" forIndexPath:indexPath];
cell.quickActionList = viewModel.quickActionsList;
cell.delegate = self;
[cell.collectionView reloadData];
return cell;
}
else
{
customClassCollectionViewCellThree *cell = [[customClassCollectionViewCellThree alloc]initWithFrame:CGRectMake(0, 0, 0, 0)];
cell = (customClassCollectionViewCellThree *)[collectionView dequeueReusableCellWithReuseIdentifier:#"GetInTouch_main_collectionview" forIndexPath:indexPath];
cell.getinTouchList = viewModel.touchList;
cell.delegate = self;
[cell.collectionView reloadData];
return cell;
}
}
just informing
custom collectionview cell class contains sub collection view again
Try adding your view components to the cell's content view and not directly as a subview.
I have two UICollectionViews in a single UIViewController. I am separating them by tag number so that I can use the data source and delegate methods for both. However, when I run the code it crashes with the Exception:
Terminating app due to uncaught exception 'NSInternalInconsistencyException', reason: 'UICollectionView received layout attributes for a cell with an index path that does not exist: <NSIndexPath: 0xc000000000200016> {length = 2, path = 0 - 1}'.
I looked this up in the forum and most people say you need to invalidate then reload the UIControllerView but in my case this is not working.
Anyone have idea how to fix this issue ?
Here is my code:
-(void)viewDidLoad {
self.socialMediaGrayIcons = [[NSMutableArray alloc] initWithObjects:[UIImage imageNamed:#"fb-gray.png"],
[UIImage imageNamed:#"twitter-gray.png"],
[UIImage imageNamed:#"insta-gray.png"],
[UIImage imageNamed:#"sms-gray.png"],
[UIImage imageNamed:#"email-gray.png"], nil];
// setup collection view
self.avatarCollectionView.tag = 200;
self.socialMediaCollectionView.tag = 201;
UINib *cellNib = [UINib nibWithNibName:#"NibCell" bundle:nil];
[self.avatarCollectionView registerNib:cellNib forCellWithReuseIdentifier:#"cvCell"];
[self.socialMediaCollectionView registerNib:cellNib forCellWithReuseIdentifier:#"smCell"];
// setup collection view layout
UICollectionViewFlowLayout *flowLayout = [[UICollectionViewFlowLayout alloc] init];
[flowLayout setItemSize:CGSizeMake(40, 40)];
[flowLayout setScrollDirection:UICollectionViewScrollDirectionHorizontal];
[self.avatarCollectionView setCollectionViewLayout:flowLayout];
[self.socialMediaCollectionView setCollectionViewLayout:flowLayout];
[self.avatarCollectionView reloadData];
[self.avatarCollectionView.collectionViewLayout invalidateLayout];
[self.socialMediaCollectionView reloadData];
[self.socialMediaCollectionView.collectionViewLayout invalidateLayout];
}
....
#pragma mark UICollectionView DataSource and Delegate mathods
- (NSInteger)numberOfSectionsInCollectionView:(UICollectionView *)collectionView
{
return 1;
}
- (NSInteger)collectionView:(UICollectionView *)collectionView numberOfItemsInSection:(NSInteger)section
{
if (collectionView.tag == 200)
{
return self.children.count;
} else if (collectionView.tag == 201){
return self.socialMediaGrayIcons.count;
}
return 1;
}
- (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath
{
UICollectionViewCell *cell;
if (collectionView.tag == 200)
{
static NSString *cellIdentifier = #"cvCell";
cell = [collectionView dequeueReusableCellWithReuseIdentifier:cellIdentifier forIndexPath:indexPath];
Child *currentChild = [self.children objectAtIndex:indexPath.row];
UIImage *curImage = [UIImage imageWithData:currentChild.thumbnail];
UIImageView *thumbView = (UIImageView *)[cell viewWithTag:100];
if (curImage != nil)
{
[thumbView setImage:curImage];
}
} else if (collectionView.tag == 201){
static NSString *cellIdentifier = #"smCell";
cell = [collectionView dequeueReusableCellWithReuseIdentifier:cellIdentifier forIndexPath:indexPath];
UIImage *curImage = (UIImage*) [self.socialMediaGrayIcons objectAtIndex:indexPath.row];
UIImageView *thumbView = (UIImageView *)[cell viewWithTag:101];
if (curImage != nil)
{
[thumbView setImage:curImage];
}
}
return cell;
}
Taking #Paulw's good advice looks like this:
#property(weak,nonatomic) IBOutlet UICollectionView *collectionViewA;
#property(weak,nonatomic) IBOutlet UICollectionView *collectionViewB;
Your datasource methods have to be religious about always dividing in two branches of a conditional based on the collection view they were passed, and always using one datasource array in one and the other in the other.
You can enforce this religion by always getting your datasource via a convenience method, like this...
- (NSArray *)datasourceForCollectionView:(UICollectionView *)collectionView {
if (collectionView == self.collectionViewA) {
return self.children;
} else { // NOTICE - no else-if, there's no other valid condition
return self.socialMediaGrayIcons;
}
}
Use it everywhere, as in...
- (NSInteger)collectionView:(UICollectionView *)collectionView numberOfItemsInSection:(NSInteger)section {
return [self datasourceForCollectionView:collectionView].count;
}
I'm populating data on uicollectionview cell and selecting and deselecting, everything works perfect but when I start scrolling sometime selection is not there sometimes selection changing with the cell. Below is the code, help much appreciated.
- (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath {
cell = (BYOCollectionCell *)[collectionView dequeueReusableCellWithReuseIdentifier:#"CVCCell" forIndexPath:indexPath];
cell.vSelectionView.hidden = YES;
cell.vSelectionView.backgroundColor = customLightGreenColor;
[self makeRoundElement:cell.vSelectionView forLabel:nil withCorner:8.0f withBorder:0];
pizzaInfo *pizzainfo= [[pizzaInfo alloc]init];
pizzainfo = [_lstDishCollection objectAtIndex: indexPath.row];
if (pizzainfo._bIsSelected)
{
cell.vSelectionView.hidden = NO;
}
else
{
cell.vSelectionView.hidden = YES;
}
//label customization
return cell;
}
DidselectItem
- (void)collectionView:(UICollectionView *)collectionView didSelectItemAtIndexPath:(NSIndexPath *)indexPath
{
cell = (BYOCollectionCell *)[collectionView dequeueReusableCellWithReuseIdentifier:#"CVCCell" forIndexPath:indexPath];
pizzaInfo *pizzaInfoCellData = [_lstDishCollection objectAtIndex: indexPath.row];
byoPizzaInfo = [_lstDishCollection objectAtIndex:indexPath.row];
if ( pizzaInfoCellData._bIsSelected)
{
cell.vSelectionView.hidden = NO;
pizzaInfoCellData._bIsSelected = NO;
[self._byodelegate deltaDeSelection:pizzaInfoCellData];
}
else
{
cell.vSelectionView.hidden = YES;
pizzaInfoCellData._bIsSelected = YES;
// deltaSelection:(pizzaInfo *)selectedItem
[self._byodelegate deltaSelection:pizzaInfoCellData];
if (self._IsNotifiable) {
[self showView];
}
}
[_vCVC reloadData];
}
More over collectionViewCell is inside tableViewCell.
In your cellForItemAtIndexPath you have already added condition for hide and show the selected view so you need to change your didSelectItemAtIndexPath like this
- (void)collectionView:(UICollectionView *)collectionView didSelectItemAtIndexPath:(NSIndexPath *)indexPath
{
pizzaInfo *pizzaInfoCellData = [_lstDishCollection objectAtIndex: indexPath.row];
if (pizzaInfoCellData._bIsSelected)
{
[self._byodelegate deltaDeSelection:pizzaInfoCellData];
}
else
{
[self._byodelegate deltaSelection:pizzaInfoCellData];
}
pizzaInfoCellData._bIsSelected = !pizzaInfoCellData._bIsSelected
[_vCVC reloadData];
}
Note:- Class name always start with uppercase latter so it is batter if you change your class name pizzaInfo with PizzaInfo, its suggestion for good coding guidelines.
Hi I am using UICollectionView that shows the input values to be entered in an array. But, the problem is that I am using a customCell of the UICollectionView inside Custom UITableViewCell. It has the problem of when the UITableView is scrolled, The number of items getting changed and the number of items not displaying properly. I've tried few third party classes like AFTabledCollectionView and HorizontalCollectionView. Please help me
//View Controller Class
-(NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
return ar.count;
}
-(NSInteger)numberOfSectionsInTableView:(UITableView *)tableView{
return 1;
}
-(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
static NSString *cellIdentifier = #"cell";
CustomCells *cell = (CustomCells *)\[tableView dequeueReusableCellWithIdentifier:cellIdentifier\];
;
if (cell == nil) {
cell = [[CustomCells alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:#"cell"\];
}
cell.lbl.text = #"Test";
cell.textLabel.textColor=[UIColor whiteColor];
[[NSUserDefaults standardUserDefaults] setInteger:[[self.array objectAtIndex:indexPath.row]count] forKey:#"r"];
cell.routelbl.text=[NSString stringWithFormat:#"Route %d",(int)indexPath.row+1];
// ... set up the cell here ...
cell.layer.cornerRadius=5;
cell.layer.masksToBounds=YES;
return cell;
}
// Custom TableViewCell
- (void)awakeFromNib {
[self.collectionview reloadData];
ViewController *v=[[ViewController alloc] init];
NSLog(#"temp %d %d ",temp,v.array.count);
f=[NSUserDefaults standardUserDefaults];
temp=(int)[f integerForKey:#"r"];
ar=[[NSMutableArray alloc] init];
[ar addObject:#"3"];
[ar addObject:#"4"];
[ar addObject:#"2"];
[ar addObject:#"1"];
UICollectionViewFlowLayout *flowLayout = [[UICollectionViewFlowLayout alloc] init];
flowLayout.scrollDirection = UICollectionViewScrollDirectionHorizontal;
flowLayout.itemSize = CGSizeMake(70, 91.0);
// \[self.collectionview setCollectionViewLayout:flowLayout\];
[self.collectionview registerNib:[UINib nibWithNibName:#"CustomCollectionViewCells" bundle:nil] forCellWithReuseIdentifier:#"cvCell2"];
self.collectionview.layer.cornerRadius=5;
self.collectionview.layer.masksToBounds=YES;
// Initialization code
}
- (void)setSelected:(BOOL)selected animated:(BOOL)animated {
[super setSelected:selected animated:animated\];
// Configure the view for the selected state
}
-(NSInteger)collectionView:(UICollectionView *)collectionView numberOfItemsInSection:(NSInteger)section{
NSLog(#"temp %d mm ",temp);
return temp;
}
-(NSInteger)numberOfSectionsInCollectionView:(UICollectionView *)collectionView{
return 1;
}
-(UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath{
temp=(int)indexPath.row;
CustomCollectionViewCells *cell = (CustomCollectionViewCells *)\[collectionView dequeueReusableCellWithReuseIdentifier:#"cvCell2" forIndexPath:indexPath\];
cell.layer.cornerRadius=5;
cell.layer.masksToBounds=YES;
return cell;
}
-(void)collectionView:(UICollectionView *)collectionView didSelectItemAtIndexPath:(NSIndexPath *)indexPath{
NSLog(#"%d",(int)indexPath.row);
}
The issue that I am facing is making number of items in the UICollectionView dynamic and discrete and also structuring the array. i.e Add new UITableViewCell and UICollectionViewCell with both addition and deletion.
UICollectionView inside UITableView works perfect when the number of rows in a table is set to be 1 and number of sections in a row is set to be NSArray's count
This is a very strange problem. I have a UICollectionView which seems to run perfectly on the iPad or the simulator as an iPad, but has a problem when running on the iPhone or iPhone simulator. The problem is that if an item is added to the datasource and I perform a reloadData, the freshly added item will not show up in the collection view. If I exit the view controller altogether and reopen it, the item is there. This problem is on the iPhone only, not the iPad, which works perfectly.
In all cases, the number of items returned is correct and the number of passes through the dequeue loop is correct (verified via debugger).
Relevant code below. I initialize the CV in viewDidAppear with the following:
UICollectionViewFlowLayout *flowLayout = [[UICollectionViewFlowLayout alloc] init];
[flowLayout setScrollDirection:UICollectionViewScrollDirectionVertical];
flowLayout.minimumInteritemSpacing = 3.0f;
UICollectionViewCell *cvCell = [[UICollectionViewCell alloc] init];
cv = [[UICollectionView alloc] initWithFrame:CGRectMake(1.0f, 80.0f, [Utility screenWidth]-2.0f, [Utility screenHeight]-60.0f) collectionViewLayout:flowLayout];
[cv setDelegate:self];
[cv setDataSource:self];
[cv setAllowsMultipleSelection:NO];
[cv setAllowsSelection:NO];
[cv setBackgroundColor: [UIColor whiteColor]];
[cv registerClass:[cvCell class] forCellWithReuseIdentifier:#"Cell"];
[self.view addSubview:cv];
[self.view sendSubviewToBack:cv];
[self queryData]; // [self queryData] also does a [cv reloadData]
The CV delegate is as follows:
-(NSInteger)numberOfSectionsInCollectionView:(UICollectionView *)collectionView
{
return 1;
}
- (NSInteger)collectionView:(UICollectionView *)collectionView numberOfItemsInSection: (NSInteger)section
{
return [cvData count];
}
- (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath
{
UICollectionViewCell *cell = [collectionView dequeueReusableCellWithReuseIdentifier:#"Cell" forIndexPath:indexPath];
[cell.contentView.subviews makeObjectsPerformSelector: #selector(removeFromSuperview)];
Item *item = (Item *) [cvData objectAtIndex:indexPath.row];
CGFloat cellSize = (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPhone) ? 100.0f : 160.0f;
ImageWithAttachedLabel *imageWithLabel = [[ImageWithAttachedLabel alloc] initWithFrame:CGRectMake(0,0,cellSize,cellSize)
withImage: [UIImage imageWithData: item.itemPhoto]
withLabel: item.itemName
roundBottoms: YES];
[cell.contentView addSubview:imageWithLabel];
return cell;
}
- (CGFloat)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout*)collectionViewLayout minimumInteritemSpacingForSectionAtIndex:(NSInteger)section
{
return 3.0f;
}
Running the debugger finds that numberOfItemsInSection is returns the CORRECT count of the items and the number of passes through the dequeue loop is correct, but the last item added (which should always be the last cell in the cv, as the items are unsorted) is not displayed.
I haven't been able to find any articles mentioning anything quite like this so I'm guessing I have a bug somewhere, but it is elusive.
Any suggestions appreciated.
Perhaps you can force the newly added item to be displayed by doing this after you add the new item to your data source:
int size = [cvData count];
NSIndexPath *lastCell = [NSIndexPath indexPathForRow:size inSection:0];
[self.collectionView insertItemsAtIndexPaths:#[lastCell]];
(assuming you point self.collectionView at your cv)