UICollectionView datasource understanding issue - ios

I have confused with datasource of UIColectionView and I really need help here.
I have array with objects [#"1", #"2", #"3", #"4", #"5", #"6"]
So I need to display them
1 2 3
4 5 6
I have found this code
- (NSInteger)numberOfSectionsInCollectionView:(UICollectionView *)collectionView
{
return noOfItem/ noOfSection;
}
- (NSInteger)collectionView:(UICollectionView *)collectionView numberOfItemsInSection:(NSInteger)section
{
return noOfSection;
}
- (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *CellIdentifier = #"cellRecipe";
collectionCell *cell = [collectionView dequeueReusableCellWithReuseIdentifier:CellIdentifier forIndexPath:indexPath];
;
Employee *emp = [array_ objectAtIndex:indexPath.section * noOfSection + indexPath.row];
cell.name.text = emp.name;
cell.image.image = emp.thumbImg;
return cell;
}
but I think it is not good use noOfItem/ noOfSection
so for example if I have 20 objects and 3 items per section
I got this error
-[__NSArrayM objectAtIndex:]: index 20 beyond bounds [0 .. 19]'
because each my section has 3 items

In my opinion you aren't quite approaching UICollectionView in the correct way.
Sections are meant to be separate sections of content, not the number of rows.
Items in section is meant to return the number of items for a given section.
In your example I would do it like this:
/**
* Called after the controller’s view is loaded into memory.
*/
- (void)viewDidLoad
{
[super viewDidLoad];
self.employees = #[[[Employee alloc] init], [[Employee alloc] init], [[Employee alloc] init], [[Employee alloc] init], [[Employee alloc] init]];
}
/**
* Asks the data source for the number of sections in the collection view.
*
* #param collectionView An object representing the collection view requesting this information.
*
* #return The number of sections in collectionView.
*/
- (NSInteger)numberOfSectionsInCollectionView:(UICollectionView *)collectionView
{
return 1;
}
/**
* Asks the data source for the cell that corresponds to the specified item in the collection view.
*
* #param collectionView An object representing the collection view requesting this information.
* #param indexPath The index path that specifies the location of the item.
*
* #return A configured cell object. You must not return nil from this method.
*/
- (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *CellIdentifier = #"cellRecipe";
collectionCell *cell = [collectionView dequeueReusableCellWithReuseIdentifier:CellIdentifier forIndexPath:indexPath];
Employee *employee = self.items[indexPath.item];
cell.name.text = employee.name;
cell.image.image = employee.thumbImg;
return cell;
}
- (NSInteger)collectionView:(UICollectionView *)collectionView numberOfItemsInSection:(NSInteger)section
{
return self.items.count;
}

With reference to an array containing [#"1", #"2", #"3", #"4", #"5", #"6"]
You don't need this method :
- (NSInteger)numberOfSectionsInCollectionView:(UICollectionView *)collectionView
Now do this :
- (NSInteger)collectionView:(UICollectionView *)collectionView numberOfItemsInSection:(NSInteger)section
{
return [self.arrayName count];
}
Now you need to set the size of cell so that each row can have 3 items. You can either set the size of cell using storyboard or you can use this method:
- (CGSize)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout *)collectionViewLayout sizeForItemAtIndexPath:(NSIndexPath *)indexPath

True. You don't really need numberOfSections... as you can solve this with sizing of cells (autolayout is your friend). If using the numberOfSectionsInCollectionView, you need to catch that the last section only has two items. You didn't include how you calculate noOfSection.
In the numberOfItems... method, you can do this:
if (section == noOfSection) {
return noOfItem % noOfSection; // Finding the remainder with modulo
} else {
return noOfItem / noOfSection;
}
I haven't tested this, but believe it should work.

Related

How to fix UICollectionView header issue?

I'm facing an issue where the header in a collection view is hiding part of the cell when an index title is selected.
It's important to indicate that the headers on the collection view are sticky.
For example, when "0" is selected, the following appears:
While I expect the following:
Notice that on the first screenshot the "0" section header is hiding the first line of the cell (which is "---- Cell Title ----").
I uploaded a sample app to Github that clearly demonstrates this issue. See https://github.com/yoasha/CollectionViewDemo
To reproduce, run the project with any iPhone simulator, select the "Collection View" option on the main page, and then tap the "0" or "1" index title.
For comparison with table view behavior, the sample app allows to select "Table View" on the main page. After that, selecting any index title will show a proper behavior of the table view in contrast to the collection view.
Any suggestions on how to fix this?
Following is the entire implementation of my collection view, which is also available on the above Github link.
#implementation MyCollectionViewController
static NSString * const reuseIdentifier = #"Cell";
- (void)viewDidLoad {
[super viewDidLoad];
UICollectionLayoutListConfiguration *config = [[UICollectionLayoutListConfiguration alloc] initWithAppearance:UICollectionLayoutListAppearancePlain];
config.headerMode = UICollectionLayoutListHeaderModeSupplementary;
self.collectionView.collectionViewLayout = [UICollectionViewCompositionalLayout layoutWithListConfiguration:config];
// Register cell classes
[self.collectionView registerClass:[UICollectionViewListCell class] forCellWithReuseIdentifier:reuseIdentifier];
[self.collectionView registerClass:[MyCollectionReusableViewHeader class]
forSupplementaryViewOfKind:UICollectionElementKindSectionHeader
withReuseIdentifier:#"header"];
}
#pragma mark <UICollectionViewDataSource>
- (NSInteger)numberOfSectionsInCollectionView:(UICollectionView *)collectionView {
return self.dataModel.count;
}
- (NSInteger)collectionView:(UICollectionView *)collectionView numberOfItemsInSection:(NSInteger)section {
return self.dataModel.count;
}
- (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath {
UICollectionViewCell *cell = [collectionView dequeueReusableCellWithReuseIdentifier:reuseIdentifier forIndexPath:indexPath];
UIListContentConfiguration *config = [((UICollectionViewListCell *)cell) defaultContentConfiguration];
config.text = #"----- Cell Title -----\nsome info\nsome info\nsome info";
cell.contentConfiguration = config;
return cell;
}
- (UICollectionReusableView *)collectionView:(UICollectionView *)collectionView viewForSupplementaryElementOfKind:(NSString *)kind atIndexPath:(NSIndexPath *)indexPath {
if ([kind isEqualToString:UICollectionElementKindSectionHeader]) {
MyCollectionReusableViewHeader *header = [self.collectionView dequeueReusableSupplementaryViewOfKind:UICollectionElementKindSectionHeader
withReuseIdentifier:#"header"
forIndexPath:indexPath];
header.text = self.dataModel[indexPath.section];
return header;
}
return nil;
}
- (NSArray<NSString *> *)indexTitlesForCollectionView:(UICollectionView *)collectionView {
return self.dataModel;
}
- (NSIndexPath *)collectionView:(UICollectionView *)collectionView indexPathForIndexTitle:(NSString *)title atIndex:(NSInteger)index {
return [NSIndexPath indexPathWithIndex:index];
}
#end
self.dataModel is NSArray<NSString *> * assigned with #[#"0", #"1", #"2", #"3", #"4"]
I also found a report of this issue at UICollectionView: How can you make the index fast-scroll to the section header instead of the first section item?

Display image in collection view by button click

I want to display random image from array in my UICollectionView. I work with xib, and already create custom cell with image view. I want that when I click my button the image displaying in collection view, but don't know how to do this. I have 2 array in tempArr I initialize images, and in arrayForImages I insert image when button press.
Here is my code:
- (IBAction)randomButton:(id)sender {
NSInteger randIndex = arc4random() % [tempArr count];
NSInteger ind = arrayForImages.count;
[arrayForImages insertObject:tempArr[randIndex] atIndex:ind];
NSLog(#"array for index %#", arrayForImages);
}
Here is the Collection
- (NSInteger)collectionView:(UICollectionView *)collectionView numberOfItemsInSection:(NSInteger)section{
return arrayForImages.count;
}
- (CGSize)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout*)collectionViewLayout sizeForItemAtIndexPath:(NSIndexPath *)indexPath {
return CGSizeMake(100, 100);
}
- (CustomCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath{
CustomCell *cell = [collectionView dequeueReusableCellWithReuseIdentifier:#"MyCell" forIndexPath:indexPath];
cell.imageViewCell.image = [UIImage imageNamed:[arrayForImages objectAtIndex:indexPath.row]];
return cell;
}

2D NSMutableArray in UICollectionView

I'm new in IOS and I don't have idea that how to populate my 2D array in collectionView.
**How Will I display following in collectionView using Labels.
myArray[0]->1,2,3,4,5
myArray[1]->6,7,8,9
myArray[2]->10,11,12,15
- (NSInteger)collectionView:(UICollectionView *)collectionView numberOfItemsInSection:(NSInteger)section
{
// What to call here as this is 2D?
return self.myArray.count;
}
- (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath
{
NSString *simpleId= #"CollectionViewCell";
TableViewCell *cell=[tableView dequeueReusableCellWithIdentifier:simpleId forIndexPath:indexPath];
//What to write here ? Cell contain 1 Label
}
Try to do like this (as #Larme suggested)-
-(UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath{
NSString *simpleId= #"CollectionViewCell";
TableViewCell *cell=[tableView dequeueReusableCellWithIdentifier:simpleId forIndexPath:indexPath];
cell.lbl.text= [NSString stringWithFormat:#"%#",[[self.myArray objectAtIndex:indexPath.section] objectAtIndex:indexPath.row]];
return cell;
}
-(NSInteger)numberOfSectionsInCollectionView:(UICollectionView *)collectionView{
return self.myArray.count;
}
-(NSInteger)collectionView:(UICollectionView *)collectionView numberOfItemsInSection:(NSInteger)section{
return [[self.myArray objectAtIndex:section] count]
}
In your 2D array myArray[0] is first section consist 5 value, myArray[1] is second section consist 4 values and myArray[2] is second section consist 5 values. So 2D Array can be easily managed by numberOfSection and numberOfItemsInSection methods. Hope this will help you..

UICollectionView inside UITableView with dynamic input (UICollectionView )

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

Collection View old icon doesn't get deselected

And I have to ask this as well. Been looking through the code for hours now and tried everything, but why does my old picture not get deselected? The user should be able to select one icon only. The selected icon is saved in Core Database. So this icon is also preselected when opening this view. However this item doesn't get deselected when he selects a new icon..why?
#import "IconSelectionCollectionViewController.h"
#import "IconSelectionCell.h"
#interface IconSelectionCollectionViewController ()
#property (nonatomic, strong) NSArray *icons;
#end
#implementation IconSelectionCollectionViewController
#synthesize mainCategory = _mainCategory;
#pragma mark Initialize model
- (void)setMainCategory:(MainCategory *)mainCategory
{
//TODO
_mainCategory = mainCategory;
self.title = mainCategory.name;
}
#pragma mark View setup
- (void)viewDidLoad
{
[super viewDidLoad];
[self.collectionView registerClass:IconSelectionCell.class forCellWithReuseIdentifier:#"IconCell"];
// Do any additional setup after loading the view.
self.icons = [NSArray arrayWithObjects:#"DefaultIcon", #"Car", #"Diploma", #"Earth", #"Flight", #"Home", #"Pen", #"Scooter", #"Ship", #"Train", nil];
self.collectionView.allowsSelection = YES;
self.collectionView.allowsMultipleSelection = NO;
}
#pragma mark Data source delegate methods
- (NSInteger)collectionView:(UICollectionView *)collectionView numberOfItemsInSection:(NSInteger)section
{
return self.icons.count;
}
- (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *identifier = #"IconCell";
IconSelectionCell *cell = [collectionView dequeueReusableCellWithReuseIdentifier:identifier forIndexPath:indexPath];
cell.iconImageView.image = [UIImage imageNamed:[self.icons objectAtIndex:indexPath.row]];
if([self.mainCategory.icon isEqualToString:[self.icons objectAtIndex:indexPath.row]]){
cell.selected = YES;
}
return cell;
}
-(NSInteger)numberOfSectionsInCollectionView:(UICollectionView *)collectionView
{
return 1;
}
#pragma mark Collection View Delegate methods
- (void)collectionView:(UICollectionView *)collectionView didSelectItemAtIndexPath:(NSIndexPath *)indexPath
{
self.mainCategory.icon = [self.icons objectAtIndex:indexPath.row];
}
#pragma mark – UICollectionViewDelegateFlowLayout
- (CGSize)collectionView:(UICollectionView *)collectionView layout:
(UICollectionViewLayout*)collectionViewLayout sizeForItemAtIndexPath:(NSIndexPath *)indexPath {
CGSize itemSize;
itemSize.height = 62;
itemSize.width = 62;
return itemSize;
}
- (UIEdgeInsets)collectionView:
(UICollectionView *)collectionView layout:(UICollectionViewLayout*)collectionViewLayout insetForSectionAtIndex:(NSInteger)section {
return UIEdgeInsetsMake(10, 10, 10, 10);
}
#end
I am not incredibly familiar with collection views, but they are very similar to table views and this is a problem that sometimes occurs with UITableviews, so I will work through a couple possible solutions.
One way to do this would be to call [self.collectionView reloadData] after the selection code. This should cause the collectionView to redraw the images, setting only one of them to be the selected image.
However, I'm not confident this would solve the problem, since dequeue reusable cells could cause the "selection" value to be set for the reused cell. So alternatively, I'd imagine you could grab both cells using UICollectionView's method cellForItemAtIndexPath: and then set their selected value in the way you set them in the main method. That may just work, but if it does not, try doing that and calling reload data again.

Resources