IOS Collection View load Image from custom cell class - ios

I am trying to implement collectionView with custom collectionViewCell class. Below code works fine, where the image is loading from Collection view class itself.
customCollectionView.m
- (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath{
static NSString *identifier = #"Cell";
MyCell *cell = (MyCell *)[collectionView dequeueReusableCellWithReuseIdentifier:identifier forIndexPath:indexPath];
UIImage *Img = [UIImage imageNamed:[Images objectAtIndex:indexPath.row]];
cell.myImageView.image = Img;
cell.layer.borderWidth=2.0f;
cell.layer.borderColor=[UIColor lightGrayColor].CGColor;
return cell;
}
MyCell.m
- (id)initWithFrame:(CGRect)frame
{
self = [super initWithFrame:frame];
if (self) {
// Initialization code
}
return self;
}
Whereas when I moved the image loading part to custom CollectionViewCell class MyCell the image is not displaying.
- (id)initWithFrame:(CGRect)frame
{
self = [super initWithFrame:frame];
if (self) {
// Initialization code
UIImage *Img = [UIImage imageNamed:#"AppIcon.png"];
_myImageView.image = Img;
}
return self;
}
My purpose is to loading different image from MyCell class in specific time interval and display on each cell.

Try to implement prepareForReuse method of UICollectionViewCell inside your customCell MyCell
-(void)prepareForReuse {
_myImageView.image = [UIImage imageNamed:#"AppIcon.png"];
}
Try awakeFromNib and remove prepareForReuse
- (void)awakeFromNib {
_myImageView.image = [UIImage imageNamed:#"AppIcon.png"];
}

Related

UICollectionView reloadData issue - cell's subview issue

I have maked following view.
But when calling -reloadData, the view becomes...
I think it's because cells is reused.
Do you have any idea to keep view as first image even if calling reloadData?
- (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath
{
CustomCell* cell = [collectionView dequeueReusableCellWithReuseIdentifier:kCellIdentifier forIndexPath:indexPath];
if (indexPath.item == 0)
{
cell.label.text = #"Hello";
}
else
{
UIImage *image = dataArray[indexPath.item];
cell.imageView.image = image;
}
return cell;
}
CustomCell.m
#property (nonatomic, strong) UIImageView* imageView;
#property (nonatomic, strong) UILabel* label;
//...
- (id)initWithFrame:(CGRect)frame
{
self = [super initWithFrame:frame];
if (self)
{
self.imageView = [[UIImageView alloc]initWithFrame:imgViewFrame];
[self.contentView addSubview:self.imageView];
self.label = [[UILabel alloc]initWithFrame:labelFrame];
[self.contentView addSubview:self.label];
}
return self;
}
EDIT:
I modified my code.
- setting all default values before setting them with correct data
- calling -prepareForReuse
When calling -reloadData, Although imageView.image stay nil, label.text in indexPath.item==0 becomes nil and label.text in indexPath.item==3 outputs #"Hello".
Yes, its because of reusability. You can avoid it by changing line of code to this:
if (indexPath.item == 0)
{
cell.label.text = #"Hello";
cell.imageView.image = nil;
}
else
{
UIImage *image = dataArray[indexPath.item];
cell.imageView.image = image;
cell.label.text = #"";
}
When you're retrieving the dequeued cells they are already setup. So the first time you retrieve 9 different cells and initialise them accordingly.
The second time tough the cells properties are already set so you need to restart them.
So your code should look as follows:
- (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath
{
CustomCell* cell = [collectionView dequeueReusableCellWithReuseIdentifier:kCellIdentifier forIndexPath:indexPath];
if (indexPath.row == 0)
{
cell.imageView.image = nil;
cell.label.text = #"Hello";
}
else
{
UIImage *image = dataArray[indexPath.item];
cell.imageView.image = image;
cell.label.text = nil;
}
return cell;
}
Try setting all default values of your cell before doing any check:
- (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath
{
CustomCell* cell = [collectionView dequeueReusableCellWithReuseIdentifier:kCellIdentifier forIndexPath:indexPath];
//Set all default values before setting them with correct data
cell.imageView.image = nil;
cell.label.text = #"";
if (indexPath.row == 0)
{
cell.label.text = #"Hello";
}
else
{
UIImage *image = dataArray[indexPath.item];
cell.imageView.image = image;
}
return cell;
}
EDIT:
You could add this method to your CustomCell.m
- (void)prepareForReuse
{
//Set default values here
}
REPORT:
I solved the issue on my own.so, I will report it.
I used the property hidden.
- (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath
{
CustomCell* cell = [collectionView dequeueReusableCellWithReuseIdentifier:kCellIdentifier forIndexPath:indexPath];
if (indexPath.item == 0)
{
cell.label.text = #"Hello";
cell.imageView.hidden = YES;
}
else
{
UIImage *image = dataArray[indexPath.item];
cell.imageView.image = image;
cell.label.hidden = YES;
}
return cell;
}

Small UIImage view in custom UICollectionViewCell

I have UICollectionViewCell
#import "DBPhotoCollectionViewCell.h"
#define IMAGEVIEW_BORDER_LENGTH 5
#implementation DBPhotoCollectionViewCell
- (id)initWithFrame:(CGRect)frame
{
self = [super initWithFrame:frame];
if (self) {
// Initialization code
[self setup];
}
return self;
}
/* Need to implement the initWithCoder method since this class will be created from the storyboard */
-(id)initWithCoder:(NSCoder *)aDecoder
{
self = [super initWithCoder:aDecoder];
if (self){
[self setup];
}
return self;
}
/* Create the UIImageView and add it to the cell's contentView in code. */
-(void)setup
{
self.imageView = [[UIImageView alloc] initWithFrame:CGRectInset(self.bounds, IMAGEVIEW_BORDER_LENGTH, IMAGEVIEW_BORDER_LENGTH)];
[self.contentView addSubview:self.imageView];
}
#end
And call this Cell from CollectionViewController class
- (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath {
static NSString *CellIdentifier = #"Photo Cell";
DBPhotoCollectionViewCell *cell = [collectionView dequeueReusableCellWithReuseIdentifier:CellIdentifier forIndexPath:indexPath];
cell.backgroundColor = [UIColor whiteColor];
cell.imageView.image = [UIImage imageNamed:#"Astronaut.jpg"];
// Configure the cell
return cell;
}
But I have one problem when I start my application my picture is showed with small size. What I missed?
http://screencast.com/t/ia8tE05P6yc
http://screencast.com/t/33N4AhT7
cell.imageView, imageView object is not same as which you have added on cell of Interface Builder. UICollectionViewCell has default size UIImageView which are accessing, you can access your customView imageView in cellForIndexPath method of collectionView by linking imageView of subClass DBPhotoCollectionViewCell in interface builder you don't need to add [self.contentView addSubview:self.imageView]; in setup method.
Second approach would be assign tag value to imageView when you adding to cell contentView
/* Create the UIImageView and add it to the cell's contentView in code. */
-(void)setup
{
self.imageView = [[UIImageView alloc] initWithFrame:CGRectInset(self.bounds, IMAGEVIEW_BORDER_LENGTH, IMAGEVIEW_BORDER_LENGTH)];
self.imageView.tag=1;
[self.contentView addSubview:self.imageView];
}
//And access imagView in cellForIndexPath
- (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath {
static NSString *CellIdentifier = #"Photo Cell";
DBPhotoCollectionViewCell *cell = [collectionView dequeueReusableCellWithReuseIdentifier:CellIdentifier forIndexPath:indexPath];
cell.backgroundColor = [UIColor whiteColor];
UIImageView *imageView=[cell.contentView viewWithTag:1];
imageView.image = [UIImage imageNamed:#"Astronaut.jpg"];
// Configure the cell
return cell;
}

View description in myUICollectionView didn't work

I'm a beginner to learn ios. It's nice to be here! I have some problem using the UICollectionView.
I've add this in myUICollectionCell.m and linked the item to storyBoard
#import "QuartzCore/QuartzCore.h"
#implementation myCollectionViewCell
#synthesize myImageView
-(instancetype)initWithFrame:(CGRect)frameRect {
self = [super initWithFrame:frameRect];
if (self) {
myImageView =[[UIImageView alloc] initWithFrame:CGRectMake(0, 200, 60, 60)];
myImageView.layer.cornerRadius = view2.frame.size.width/2;
myImageView.layer.masksToBounds = YES;
[self.contentView addSubview:myImageView];
}
return self;
}
#end
ViewController.m
#import "myCollectionViewCell.h"
-(UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath{
static NSString * CellIdentifier = #"cell";
myCollectionViewCell *cell = (myCollectionViewCell*)[collectionView dequeueReusableCellWithReuseIdentifier:CellIdentifier forIndexPath:indexPath];
cell.myImageview.image = [UIImage imageNamed:#"2.jpg"];
return cell;
}
myImageView still didn't change to circle as I described.
It can only work when I put the description into collectionView:cellForItemAtIndexPath:
-(UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath{
static NSString * CellIdentifier = #"cell";
myCollectionViewCell *cell = (myCollectionViewCell*)[collectionView dequeueReusableCellWithReuseIdentifier:CellIdentifier forIndexPath:indexPath];
cell.myImageview.image = [UIImage imageNamed:#"2.jpg"];
myImageView.layer.cornerRadius = view2.frame.size.width/2;
myImageView.layer.masksToBounds = YES;
return cell;
}
why is that? I'm confusing with the place where I should describe my view on my cell.
It seems you are using xib or storyboard, so it won't call initWithFrame: of UICollectionViewCell.
Using awakeFromNib instead:
-(void)awakeFromNib
{
[super awakeFromNib];
//Is myImageView an outlet of storyboard? if it is you needn't realloc a UIImageView instance
//myImageView =[[UIImageView alloc] initWithFrame:CGRectMake(0, 200, 60, 60)];
myImageView.layer.cornerRadius = 5.0;
myImageView.layer.masksToBounds = YES;
//[self.contentView addSubview:myImageView];
}

UICollectionview is empty

Hi i have created one UIViewController in that i added one UICollectionView with CustomCell. Then, i created a uicollectionviewcell class for cell. Finally set the delegate and datasource in storybord itself. But it showing empty page. like in below image
CODE:
- (void)viewDidLoad
{
[super viewDidLoad];
self.collectionview = _collectionview;
self.collectionview.dataSource = self;
self.collectionview.delegate = self;
speakersImages=[[NSMutableArray alloc]init];
// Do any additional setup after loading the view, typically from a nib.
imageLabels=[[NSMutableArray alloc]initWithObjects:#"RB Forum 2013",#"Agenda",#"Speakers",#"Contact",#"Map",#"Websites",#"#Responsible Biz",#"Partners",#"Sustainability",nil];
imagePaths=[[NSMutableArray alloc]initWithObjects:[UIImage imageNamed:#"RBform.png"],[UIImage imageNamed:#"agenda.png"],[UIImage imageNamed:#"speakers.png"],[UIImage imageNamed:#"contact.png"],[UIImage imageNamed:#"map.png"],[UIImage imageNamed:#"website.png"],[UIImage imageNamed:#"twitter.png"],[UIImage imageNamed:#"partners.png"],[UIImage imageNamed:#"sustainability.png"], nil];
[self.collectionview registerClass:[NewCell class] forCellWithReuseIdentifier:#"Cell"];
}
- (NSInteger)numberOfSectionsInCollectionView:(UICollectionView *)collectionView
{
return 1;
}
- (NSInteger)collectionView:(UICollectionView *)collectionView
numberOfItemsInSection:(NSInteger)section
{
return [imageLabels count];
}
//THE BELOW DELEGATE METHOD DOES NOT GET CALLED!
- (void)didReceiveMemoryWarning
{
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
- (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath
{
// we're going to use a custom UICollectionViewCell, which will hold an image and its label
//
static NSString *CellIdentifier = #"Cell";
NewCell *cell = [collectionView dequeueReusableCellWithReuseIdentifier:CellIdentifier forIndexPath:indexPath];
// make the cell's title the actual NSIndexPath value
cell.labels.text = [NSString stringWithFormat:#"%#",[imageLabels objectAtIndex:indexPath.row]];
// load the image for this cell
NSLog(#"%#",imageLabels);
//NSString *imageToLoad = [NSString stringWithFormat:#"%d.JPG", indexPath.row];
// cell.image.image = [UIImage imageNamed:imageToLoad];
cell.images.image = [imagePaths objectAtIndex:indexPath.row];
return cell;
}
Solution is remove
[self.collectionview registerClass:[NewCell class] forCellWithReuseIdentifier:#"Cell"];
in storybord we dont need this
Code is ok but order is different.Assigning datasource and delegates before array is populated makes the number of cell returned to 0 ,since array is not yet populated
Try like this
speakersImages=[[NSMutableArray alloc]init];
// Do any additional setup after loading the view, typically from a nib.
imageLabels=[[NSMutableArray alloc]initWithObjects:#"RB Forum 2013",#"Agenda",#"Speakers",#"Contact",#"Map",#"Websites",#"#Responsible Biz",#"Partners",#"Sustainability",nil];
imagePaths=[[NSMutableArray alloc]initWithObjects:[UIImage imageNamed:#"RBform.png"],[UIImage imageNamed:#"agenda.png"],[UIImage imageNamed:#"speakers.png"],[UIImage imageNamed:#"contact.png"],[UIImage imageNamed:#"map.png"],[UIImage imageNamed:#"website.png"],[UIImage imageNamed:#"twitter.png"],[UIImage imageNamed:#"partners.png"],[UIImage imageNamed:#"sustainability.png"], nil];
[self.collectionview registerClass:[NewCell class] forCellWithReuseIdentifier:#"Cell"];
[self.collectionview reloadData];
this line is not needed
self.collectionview = _collectionview;
self.collectionview.dataSource = self;
self.collectionview.delegate = self;
also make sure your collection view is connected via outlet
make sure the <UICollectioniewDatasource,UICollectionviewDelegate> is there in the class header
In Your storyboard give your imageview a tag e.g. 1, and your label another tag e.g. 2
Give your cell reuse identifier that you have already gave eg. "Cell"
Now in your storyboard right click on collection view and create datasource and delegate to your viewController or file owner. alternatively you can use <UICollectionViewDataSource,UICollectionViewDelegate> in your viewController and set the delegate and datasource to self.
Now in your viewDidLoad
-(void) viewDidLoad {
self.collectionview.dataSource = self;
self.collectionview.delegate = self;
speakersImages=[[NSMutableArray alloc]init];
// Do any additional setup after loading the view, typically from a nib.
imageLabels=[[NSMutableArray alloc]initWithObjects:#"RB Forum 2013",#"Agenda",#"Speakers",#"Contact",#"Map",#"Websites",#"#Responsible Biz",#"Partners",#"Sustainability",nil];
imagePaths=[[NSMutableArray alloc]initWithObjects:[UIImage imageNamed:#"RBform.png"],[UIImage imageNamed:#"agenda.png"],[UIImage imageNamed:#"speakers.png"],[UIImage imageNamed:#"contact.png"],[UIImage imageNamed:#"map.png"],[UIImage imageNamed:#"website.png"],[UIImage imageNamed:#"twitter.png"],[UIImage imageNamed:#"partners.png"],[UIImage imageNamed:#"sustainability.png"], nil];
}
number of items in collection view
(NSInteger)collectionView:(UICollectionView *)collectionView
numberOfItemsInSection:(NSInteger)section
{
return [imageLabels count];
}
create cell and reuse
(UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath
{
UICollectionView *cell = [collectionView dequeueReusableCellWithReuseIdentifier:#"Cell"];
// make the cell's title the actual NSIndexPath value
UIlabel *label = (UIlabel *) [cell viewWithTag:2]
label.text = [NSString stringWithFormat:#"%#",[imageLabels objectAtIndex:indexPath.row]];
// load the image for this cell
UIImageView *imageView = (UIImageView *) [cell viewWithTag:1]
imageView.image = [imagePaths objectAtIndex:indexPath.row];
return cell;
}
- (void)viewDidLoad
{
[super viewDidLoad];
[self.collectionView registerNib:[UINib nibWithNibName:#"NewCell" bundle:nil] forCellWithReuseIdentifier:#"CELL"];
self.collectionview.dataSource = self;
self.collectionview.delegate = self;
self.imageLabels = [NSArray arrayWithObjects:#"RB Forum 2013",#"Agenda",#"Speakers",#"Contact",#"Map",#"Websites",#"#Responsible Biz",#"Partners",#"Sustainability",nil];
self.imagePaths=[NSArray arrayWithObjects::#"RBform.png",#"agenda.png",#"speakers.png",#"contact.png",#"map.png",#"website.png",#"twitter.png",#"partners.png",#"sustainability.png", nil];
}
- (NSInteger)collectionView:(UICollectionView *)collectionView
numberOfItemsInSection:(NSInteger)section
{
return [self.imageLabels count];
}
- (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath
{
NewCell *cell = [collectionView dequeueReusableCellWithReuseIdentifier:#"CELL" forIndexPath:indexPath];
cell.labels.text = [self.imageLabels objectAtIndex:indexPath.row]];
cell.images.image = [UIImage imageNamed:[self.imagePaths objectAtIndex:index path.row]];
return cell;
}

iOS UICollectionViewPerformance issue

I am trying to create a simple collection view with custom cells that have an UIImageView as a background. It's going to look something like :
This is my code :
ViewController.m
- (void)viewDidLoad
{
[super viewDidLoad];
[self.collectionView registerClass:[MyCell class] forCellWithReuseIdentifier:#"MY_CELL"];
leftInset = rightInset = 0;
numberOfDays = 31;
// Do any additional setup after loading the view, typically from a nib.
}
- (void)didReceiveMemoryWarning
{
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
-(NSInteger)numberOfSectionsInCollectionView:(UICollectionView *)collectionView
{
return 200;
}
- (NSInteger)collectionView:(UICollectionView *)view numberOfItemsInSection:(NSInteger)section
{
return numberOfDays;
}
- (UICollectionViewCell *)collectionView:(UICollectionView *)cv cellForItemAtIndexPath:(NSIndexPath *)indexPath;
{
MyCell *cell = [cv dequeueReusableCellWithReuseIdentifier:#"MY_CELL" forIndexPath:indexPath];
if(indexPath.row < 10)
cell.imageView.image = [UIImage imageNamed:#"no"];
else if(indexPath.section%3==1)
{
cell.imageView.image = [UIImage imageNamed:#"ok"];
}
else if(indexPath.section%3==2)
{
cell.imageView.image = [UIImage imageNamed:#"sa"];
}
else{
cell.imageView.image = [UIImage imageNamed:#"happy_vote"];
}
return cell;
}
#pragma mark – UICollectionViewDelegateFlowLayout
- (CGSize)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout*)collectionViewLayout sizeForItemAtIndexPath:(NSIndexPath *)indexPath {
return CGSizeMake(CELL_DIM, CELL_DIM);
}
- (UIEdgeInsets)collectionView:
(UICollectionView *)collectionView layout:(UICollectionViewLayout*)collectionViewLayout insetForSectionAtIndex:(NSInteger)section {
// top left bottom right
return UIEdgeInsetsMake(5, leftInset, 0, 0);
}
MyCell.m
- (id)initWithFrame:(CGRect)frame
{
self = [super initWithFrame:frame];
if (self) {
NSLog(#"Init with frame!");
self.imageView = [[UIImageView alloc] initWithFrame:CGRectMake(0.0, 0.0, frame.size.width, frame.size.height)];
[self.contentView addSubview:self.imageView];
[self.imageView setBackgroundColor:[UIColor redColor]];
}
return self;
}
It works fine for around 10 sections in the collection view. The problem is when I want to add more sections, the vertical scrolling starts to move really slow. I noticed that all the cells are allocated all at once. I am searching for a way to make this more resource friendly, and have the scrolling move continuously rather than slow and laggish. Could you tell me how to take care of the resources allocation to avoid this problem ? Thank you.
PS : I've tried removing the image view from the cell background and in the method cellForItemAtIndexPath: set a background color for the cell but again, after 10 or more sections it moves really slow.
What you might want to do to help performance time is to check if an object is already initiated. You could also separately instantiate your images so that it doesnt have to be read from memory every time:
Make image1 a property of the view controller:
- (void)viewDidLoad
{
image1 = [UIImage imageNamed:#"image1"];
image2 = [UIImage imageNamed:#"image2"];
image3 = [UIImage imageNamed:#"image3"];
}
- (UICollectionViewCell *)collectionView:(UICollectionView *)cv cellForItemAtIndexPath:(NSIndexPath *)indexPath;
{
MyCell *cell = [cv dequeueReusableCellWithReuseIdentifier:#"MY_CELL" forIndexPath:indexPath];
if(indexPath.row < 10)
cell.imageView.image = [UIImage imageNamed:#"no"];
else if(indexPath.section%3==1)
{
cell.imageView.image = image1;
}
else if(indexPath.section%3==2)
{
cell.imageView.image = image2;
}
else{
cell.imageView.image = image3;
}
return cell;
}

Resources