How to initialize UICollectionViewCell programmatically without Nib - ios

I decided to opt out of using a Xib to generate my custom UICollectionViewCell (StoneCell), so I've been struggling with how to go about properly initializing it programmatically.
I implemented:
- (CGSize)collectionView:(UICollectionView *)collectionView
layout:(UICollectionViewLayout *)collectionViewLayout
sizeForItemAtIndexPath:(NSIndexPath *)indexPath {
CGSize size = [MainScreen screen];
CGFloat width = size.width;
CGFloat item = (width*60)/320;
return CGSizeMake(item, item);
}
as well as:
[self.collectionView registerClass:[StoneCell class] forCellWithReuseIdentifier:#"stoneCell"];
in my UICollectionView controller.
In my StoneCell.m, I tried the following:
-(id)initWithFrame:(CGRect)frame {
self = [super initWithFrame:frame];
if (self) {
StoneCell* stone = [[StoneCell alloc] initWithFrame:frame];
self = stone;
}
return self;
}
but to no avail. When I build and run, I crash on self = [super initWithFrame:frame]; When I check the value of frame, it's correctly set at {{0,0},{70,70}} which is what it should be on the 6s. However, the object stone (as well as self) are both reported as nil.
Clearly this is not correct, so I wanted to know how to initialize the cell properly.
I am also properly dequeuing the cell in:
-(UICollectionViewCell *)collectionView:(UICollectionView *)collectionView
cellForItemAtIndexPath:(NSIndexPath *)indexPath
so that's taken care of.

Your initializer should be
- (instancetype)initWithFrame:(CGRect)frame {
self = [super initWithFrame:frame];
return self;
}
With your original implementation
-(id)initWithFrame:(CGRect)frame {
self = [super initWithFrame:frame];
if (self) {
StoneCell* stone = [[StoneCell alloc] initWithFrame:frame];
self = stone;
}
return self;
}
you have an infinite recursion of initWithFrame.

// In AMAImageViewCell.h
#import <UIKit/UIKit.h>
#interface AMAImageViewCell : UICollectionViewCell
#property (strong, readonly, nonatomic) UIImageView *imageView;
#end
// In AMAImageViewCell.m
#implementation AMAImageViewCell
- (id)initWithFrame:(CGRect)frame
{
self = [super initWithFrame:frame];
if (self) {
_imageView = [[UIImageView alloc] initWithFrame:self.contentView.bounds];
_imageView.autoresizingMask = UIViewAutoresizingFlexibleHeight | UIViewAutoresizingFlexibleWidth;
_imageView.clipsToBounds = YES;
_imageView.contentMode = UIViewContentModeScaleAspectFill;
_imageView.layer.cornerRadius = 0.0;
[self.contentView addSubview:_imageView];
}
return self;
}
#end
/******In the class where you have to use **********/
[self.collectionView registerClass:[AMAImageViewCell class] forCellWithReuseIdentifier:ImageCellIdentifier];
// In cellForItemAtIndexPath
AMAImageViewCell *cell = [collectionViewLocal dequeueReusableCellWithReuseIdentifier:ImageCellIdentifier
forIndexPath:indexPath];

Related

Imageview is not showing up in a programmatically created collectionview

I am having a hard time figuring out why cell.imageview property doesn't show me image below. UIImage is not nil, cells are created, if I assign a background to cell, it is displayed which proves I am creating collectionview and my cells correctly. I programmatically create my collectionview and don't use any IB or interface builder. I have done this lots of times before, but I am really scratching my head with this one.
Thanks in advance.
#interface MainViewController : UIViewController
#property(strong, nonatomic) UICollectionView *collectionView;
#end
#interface MainViewController ()<
UICollectionViewDataSource, UICollectionViewDelegate,
UICollectionViewDelegateFlowLayout, UIGestureRecognizerDelegate>
#property(nonatomic, strong) MHTransitionShowDetail *interactivePushTransition;
#property(nonatomic) CGPoint lastPoint;
#property(nonatomic) CGFloat startScale;
#property(strong, nonatomic) NSMutableArray *carImages;
#end
#implementation MainViewController
- (instancetype)init {
self = [super init];
if (self) {
}
return self;
}
- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
_carImages = [#[
#"chevy_small",
#"mini_small",
#"rover_small",
#"smart_small",
#"highlander_small",
#"venza_small",
#"volvo_small",
#"vw_small",
#"ford_small",
#"nissan_small"
] mutableCopy];
self.view = [[UIView alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
UICollectionViewFlowLayout *layout =
[[UICollectionViewFlowLayout alloc] init];
layout.itemSize = CGSizeMake(106, 106);
layout.minimumLineSpacing = 1.0;
layout.minimumInteritemSpacing = 1.0;
self.collectionView = [[UICollectionView alloc] initWithFrame:self.view.frame
collectionViewLayout:layout];
[self.collectionView setDataSource:self];
[self.collectionView setDelegate:self];
self.collectionView.alwaysBounceVertical = YES;
[self.collectionView setContentInset:UIEdgeInsetsMake(20, 10, 10, 10)];
[self.collectionView registerClass:[IKGCollectionViewCell class]
forCellWithReuseIdentifier:#"myCell"];
self.collectionView.backgroundColor = [UIColor whiteColor];
[self.view addSubview:self.collectionView];
}
- (void)didReceiveMemoryWarning {
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
#pragma CollectionView & FlowLayout methods
- (CGSize)collectionView:(UICollectionView *)collectionView
layout:(UICollectionViewLayout *)collectionViewLayout
sizeForItemAtIndexPath:(NSIndexPath *)indexPath {
return CGSizeMake(120, 120);
}
- (NSInteger)collectionView:(UICollectionView *)collectionView
numberOfItemsInSection:(NSInteger)section {
return self.carImages.count;
}
- (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView
cellForItemAtIndexPath:(NSIndexPath *)indexPath {
IKGCollectionViewCell *cell =
[collectionView dequeueReusableCellWithReuseIdentifier:#"myCell"
forIndexPath:indexPath];
long row = [indexPath row];
UIImage *image = [UIImage imageNamed:self.carImages[row]];
cell.imageView.userInteractionEnabled = YES;
cell.imageView.image = image;
NSLog(#"cell.image view %#", image);
// [self makeCell:(IKGCollectionViewCell *)cell atIndexPath:indexPath];
return cell;
}
}
#end
#interface IKGCollectionViewCell : UICollectionViewCell
#property(nonatomic, strong) UIImageView *imageView;
#end
#implementation IKGCollectionViewCell
- (id)initWithFrame:(CGRect)frame {
self = [super initWithFrame:frame];
if (self) {
self.imageView = [[UIImageView alloc] initWithFrame:self.bounds];
NSLog(#"self.bounds is %#", NSStringFromCGRect(self.bounds));
}
return self;
}
- (void)layoutSubviews {
[super layoutSubviews];
self.imageView.frame = self.contentView.bounds;
}
#end
You missed to add the cell's imageView as a it's subview.
So in cell's initWithFrame
- (id)initWithFrame:(CGRect)frame {
self = [super initWithFrame:frame];
if (self) {
self.imageView = [[UIImageView alloc] initWithFrame:self.bounds];
//Add imageView as subview
[self addSubview:self.imageView];
NSLog(#"self.bounds is %#", NSStringFromCGRect(self.bounds));
}
return self;
}

UICollectionViewCell issues with registerClass

I am trying to create a collection view cell programmatically without the use of storyboards or nibs.
This is my cell .h file
#import <UIKit/UIKit.h>
#interface TestCVCell : UICollectionViewCell {
UILabel *label;
}
#property (nonatomic, retain) UILabel *label;
#end
and this is the .m file
#import "TestCVCell.h"
#implementation TestCVCell
#synthesize label;
- (instancetype)initWithFrame:(CGRect)frame
{
self = [super initWithFrame:frame];
if (self) {
if (!self.label) {
label = [[UILabel alloc] initWithFrame:self.frame];
label.textColor = [UIColor whiteColor];
self.contentView.backgroundColor = [UIColor orangeColor];
[self.contentView addSubview:label];
}
}
return self;
}
- (void)prepareForReuse
{
self.label.text = #"";
}
#end
The issue I am having is that when I register class, it sporadically shows the cells and it doesn't show them at the correct locations. The cells will also randomly disappear/appear while scrolling (often not in the same location).
The weird thing is, if I create a nib and register the nib as opposed to the class, everything works perfectly fine.
The only difference I can think of between the nib and the class is with the nib, I use -(id)initWithCoder:(NSCoder *)aDecoder instead of -(instancetype)initWithFrame:(CGRect)frame.
Here is the collection view files for reference
.h
#import <UIKit/UIKit.h>
#interface TestCollectionView : UICollectionView
#end
.m
#import "TestCollectionView.h"
#import "TestCVCell.h"
#interface TestCollectionView () <UICollectionViewDataSource>
#property (nonatomic, strong) NSMutableArray *itemArray;
#end
#implementation TestCollectionView
- (instancetype)initWithFrame:(CGRect)frame
{
self = [super initWithFrame:frame collectionViewLayout:[self collectionViewLayout]];
if (self) {
[self registerClass:[TestCVCell class] forCellWithReuseIdentifier:#"cell"];
self.itemArray = [[NSMutableArray alloc] init];
self.dataSource = self;
for (int idx = 0; idx < 50; idx++) {
[self.itemArray addObject:[NSNumber numberWithInt:idx]];
}
}
return self;
}
- (NSInteger)numberOfSectionsInCollectionView:(UICollectionView *)collectionView
{
return 1;
}
- (NSInteger)collectionView:(UICollectionView *)collectionView numberOfItemsInSection:(NSInteger)section
{
return self.itemArray.count;
}
- (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath
{
TestCVCell *cell = (TestCVCell *)[collectionView dequeueReusableCellWithReuseIdentifier:#"cell" forIndexPath:indexPath];
cell.label.text = [NSString stringWithFormat:#"%#", [self.itemArray objectAtIndex:indexPath.item]];
return cell;
}
- (UICollectionViewLayout *)collectionViewLayout
{
UICollectionViewFlowLayout *layout = [[UICollectionViewFlowLayout alloc] init];
layout.itemSize = CGSizeMake(50, 50);
return layout;
}
#end
Has anyone ever encountered this issue or something similar?
Thanks in advanced for the help.
Here is your problem, Your TestCVCell Class is initializing the label during init, then the collectionView is reusing the same cell, remember during reuse we don't initialize a new object, we just recycle an existing one, therefore your label is never set up on subsequent reuse. Make the following changes to your TestCVCell class.
TestCVCell.h
#interface TestCVCell : UICollectionViewCell
#property (nonatomic) UILabel *label;
#end
You don't need the iVar label anymore. We'll use the automatically synthesized _label iVar if need be.
Use lazy loading to initialize the label, its not only clever but a cleaner alternative, customize the getter to look like below, also remember to call super on prepareForReuse
#import "TestCVCell.h"
#implementation TestCVCell
- (UILabel *)label {
if (!_label) {
_label = [[UILabel alloc] initWithFrame:self.bounds];
_label.textColor = [UIColor whiteColor];
_label.textAlignment = NSTextAlignmentCenter;
self.contentView.backgroundColor = [UIColor orangeColor];
[self.contentView addSubview:_label];
}
return _label;
}
- (void)prepareForReuse
{
[super prepareForReuse];
self.label.text = #"";
}
#end
The above code only adds the label to the contentView if its not been initialized before, it will only initialize a new one when needed, thus lazy loading. Delete your entire init method, it's not needed. The above is your entire implementation of TestCVCell. Clean and easy to understand.

Creating a UICollectionView within a subview

I have a view controller (that sits in a tab bar controller), but need to add a collection view to that controller. I see lots of tutorials on google but they all seem to point to creating a UICollectionViewController and starting in viewDidLoad. But how do I do it in a subview?
I have my view controller.m file like so:
- (void) createView // called from viewDidLoad
{
UIScrollView *scrollView = [[UIScrollView alloc] initWithFrame:CGRectMake(0.0, 64.0, screenWidth, screenHeight)];
[scrollView.layer addGradient];
ACollectionView *theview = [[ACollectionView alloc] init];
[self.view addSubview:theview];
}
Next I started a UICollectionView subclass called ACollectionView.h
#interface ACollectionView : UICollectionView
#end
And the .m file is this:
#import "ACollectionView.h"
#implementation BestCollectionView
- (id)initWithFrame:(CGRect)frame
{
self = [super initWithFrame:frame];
if (self) {
// Initialization code
}
return self;
}
Where do I start the collection view, in the initWithFrame?
I am trying to follow this:
Creating a UICollectionView programmatically
Is my paradigm correct?
#property (nonatomic, strong) UICollectionView *collectionView;
- (void)viewDidLoad
{
[super viewDidLoad];
UICollectionViewFlowLayout *layout = [[UICollectionViewFlowLayout alloc] init];
self.collectionView = [[UICollectionView alloc] initWithFrame:self.yourSubview.frame collectionViewLayout:layout];
[self.collectionView setDataSource:self];
[self.collectionView setDelegate:self];
[self.collectionView registerClass:[UICollectionViewCell class] forCellWithReuseIdentifier:#"cellIdentifier"];
[self.yourSubview addSubview:self.collectionView];
}
- (NSInteger)collectionView:(UICollectionView *)collectionView numberOfItemsInSection:(NSInteger)section
{
return 50;
}
- (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath
{
UICollectionViewCell *cell=[collectionView dequeueReusableCellWithReuseIdentifier:#"cellIdentifier" forIndexPath:indexPath];
cell.backgroundColor = [UIColor redColor];
return cell;
}
- (CGSize)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout*)collectionViewLayout sizeForItemAtIndexPath:(NSIndexPath *)indexPath
{
return CGSizeMake(100, 100);
}

ios uiviewcontroller with collectionview subview not showing cells

I have a uiviewcontroller with a subview which is a uicollection view. My view controller implements all of the collectionview delegates. For some reason some of the cells are black (when i scroll they appear , it seems randomly) My code is:
#import "NewGalleryViewController.h"
#interface MyCell : UICollectionViewCell
#property (nonatomic,strong) UIImageView *imageView;
#end
#implementation MyCell
-(id)initWithFrame:(CGRect)frame
{
self = [super initWithFrame:frame];
NSLog(#"frame = %#\n", NSStringFromCGRect(frame));
if (self)
{
self.imageView = [[UIImageView alloc] initWithFrame:frame];
[self.contentView addSubview:self.imageView];
}
return self;
}
#end
#interface NewGalleryViewController () <UICollectionViewDelegate,UICollectionViewDataSource,UICollectionViewDelegateFlowLayout>
#property (nonatomic,strong) UICollectionView *collectionView;
#end
#implementation NewGalleryViewController
- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil
{
self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
if (self) {
// Custom initialization
}
return self;
}
- (void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view.
UICollectionViewFlowLayout *layout = [[UICollectionViewFlowLayout alloc] init];
[layout setItemSize:CGSizeMake(75, 75)];
self.collectionView = [[UICollectionView alloc] initWithFrame:self.view.bounds collectionViewLayout:layout];
self.collectionView.delegate = self;
self.collectionView.dataSource = self;
[self.collectionView registerClass:[MyCell class] forCellWithReuseIdentifier:#"newcell"];
[self.view addSubview:self.collectionView];
}
- (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 100;
}
- (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath
{
MyCell *cell = [collectionView dequeueReusableCellWithReuseIdentifier:#"newcell" forIndexPath:indexPath];
cell.imageView.image = [UIImage imageNamed:#"114"];
return cell;
}
-(void)collectionView:(UICollectionView *)collectionView didDeselectItemAtIndexPath:(NSIndexPath *)indexPath
{
NSLog(#"%ld",(long)indexPath.row);
}
- (CGSize)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout*)collectionViewLayout sizeForItemAtIndexPath:(NSIndexPath *)indexPath
{
return CGSizeMake(75,75);
}
- (UIEdgeInsets)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout*)collectionViewLayout insetForSectionAtIndex:(NSInteger)section
{
return UIEdgeInsetsMake(0, 0, 0, 0);
}
- (CGFloat)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout*)collectionViewLayout minimumLineSpacingForSectionAtIndex:(NSInteger)section
{
return 10;
}
- (CGFloat)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout*)collectionViewLayout minimumInteritemSpacingForSectionAtIndex:(NSInteger)section
{
return 0;
}
#end
I fixed your problem
-(id)initWithFrame:(CGRect)frame
{
self = [super initWithFrame:frame];
if (self)
{
self.imageView = [[UIImageView alloc] initWithFrame:self.bounds]; // earlier it was frame
[self.contentView addSubview:self.imageView];
}
return self;
}
While creating the content image view do not use frame of the cell instead of use self.bounds. Iam not sure about the reason. Frame can be different at that time bounds will give the actual values
- (id)initWithFrame:(CGRect)frame
{
self = [super initWithFrame:frame];
if (self) {
// Initialization code
NSArray *arrayOfviews = [[NSBundle mainBundle]loadNibNamed:#"PersonCollectionViewCell" owner:self options:nil];
self = [[arrayOfviews objectAtIndex:0]isKindOfClass:[UICollectionViewCell class]] ? [arrayOfviews objectAtIndex:0] : nil;
}
return self;
}

issue with using multiple cell types in uitableview

I am using this code for multiple cell types in a UITableView
The problem is that the cell text is invisible. The code for cellForRowAtIndexPath as well as the cell class code is given below:
code:
static NSString *kCellIdentifier = #"NewsViewControllerTableCell";
static NSString *kCellIdentifier2 = #"SubscribeCell";
if ((indexPath.row==0) && ([[NSUserDefaults standardUserDefaults] boolForKey:#"subscribeButtonOption"]))
{
SubscribeCell* cell = (SubscribeCell*)[tableView dequeueReusableCellWithIdentifier:kCellIdentifier2];
if (cell == nil) {
cell = [[[SubscribeCell alloc] initWithFrame:CGRectMake(0.0, 0.0, 320.0, 35.0) reuseIdentifier:kCellIdentifier2] autorelease];
cell.contentView.backgroundColor = kColorR53G53B53;
cell.subscribeLabel.font = kLucidaSansStdFontBold_14;
cell.subscribeLabel.textColor = [UIColor whiteColor];
}
cell.subscribeLabel.textColor=[UIColor redColor];
cell.subscribeLabel.text = #"+ SUBSCRIBE TO NEWSLETTER";
cell.selectedBackgroundView = [[[UIView alloc] initWithFrame:CGRectZero] autorelease];
cell.selectedBackgroundView.backgroundColor =kColorR53G53B53;
[cell setNeedsDisplay];
return cell;
}
else
{
//another cell
}
=========
header:
#import <UIKit/UIKit.h>
#interface SubscribeCell : UITableViewCell{
UILabel *subscribeLabel;
}
#property(nonatomic, retain) UILabel *subscribeLabel;
#end
and implementation class:
#import "SubscribeCell.h"
#implementation SubscribeCell
#synthesize subscribeLabel;
- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil
{
self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
if (self) {
// Custom initialization
subscribeLabel=[[UILabel alloc] initWithFrame:CGRectMake(0.0, 0.0, 323.0, 40.0)];
subscribeLabel.textColor=[UIColor whiteColor];
self.backgroundColor=kColorR53G53B53;
}
return self;
}
Check to see if subscribeLabel is nil. You're creating it in initWithNibName:bundle: but are initializing with initWithFrame:reuseIdentifier:, so it's not reaching your label creation code.
If I try to compile your code, I get an error message stating that UITableViewCell does not declare a method called 'initWithNibName: bundle:'. You should use the proper initialization method 'initWithStyle: reuseIdentifier:'. You also forget to add the subscribeLabel to the contentView of the cell.
- (id)initWithStyle:(UITableViewCellStyle)style reuseIdentifier:(NSString *)reuseIdentifier
{
self = [super initWithStyle:style reuseIdentifier:reuseIdentifier];
if (self) {
subscribeLabel=[[UILabel alloc] initWithFrame:CGRectMake(0.0, 0.0, 323.0, 40.0)];
subscribeLabel.textColor=[UIColor whiteColor];
[self.contentView addSubview:subscribeLabel];
self.backgroundColor=kColorR53G53B53;
}
return self;
}

Resources