I have created nib with custom tableViewCell.
Created Class TableViewCellSimple for it with black label color.
Now I want to subclass this cell and get red color of label.
So, I create subclass of it TableViewCellRedColor and override init method.
- (void)setup
{
[super setup];
self.titleLabel.textColor = [UIColor k_mainRed];
}
In my VC, I register this 2 cells:
[self.tableView registerNib:[UINib nibWithNibName:#"TableViewCellSimple" bundle:nil] forCellReuseIdentifier:kCellIdentifier_ TableViewCellSimple];
[self.tableView registerNib:[UINib nibWithNibName:#"TableViewCellRedColor" bundle:nil] forCellReuseIdentifier:kCellIdentifier_ TableViewCellRedColor];
And then I creating cells:
switch (indexPath.row) {
case 0:
{
TableViewCellSimple *cell = (TableViewCellSimple *)[self.tableView dequeueReusableCellWithIdentifier:kCellIdentifier_ TableViewCellSimple];
cell.titleLabel.text = NSLocalizedString(#"Clear All Messages", nil);
return cell;
}
break;
case 1:
{
TableViewCellRedColor *cell = (TableViewCellRedColor *)[self.tableView dequeueReusableCellWithIdentifier:kCellIdentifier_ TableViewCellRedColor];
cell.titleLabel.text = NSLocalizedString(#"Leave Chat and Event", nil);
return cell;
}
break;
But I did not get red color. I debug my code and overridden method did not called.
Why?
Related
Actually, I wanted to add multiple xib files to a single UIcollectionview . I have switch case to assign different collectionviewcell for different indexpath. I have not got any clear ideas how to make it possible.
CollectionCell *cell1;
switch (indexPath.row) {
case 0:
[self.Collection registerNib:[UINib nibWithNibName:#"CCollectionCell" bundle:nil] forCellWithReuseIdentifier:#"board"];
cell1 = [collectionView dequeueReusableCellWithReuseIdentifier:#"dashboard" forIndexPath:indexPath];
return cell1;
break;
}
You code style doesn't work because indexPath.row is not fixed param for the swift, so do code like below :
in viewDidLoad
[self.collectionView registerNib:[UINib nibWithNibName:#"CustomCell0" bundle:nil] forCellWithReuseIdentifier:#"MyCell0"];
[self.collectionView registerNib:[UINib nibWithNibName:#"CustomCell1" bundle:nil] forCellWithReuseIdentifier:#"MyCell1"];
// do same for all your six xib
in numberofItems
- (NSInteger)collectionView:(UICollectionView *)collectionView numberOfItemsInSection:(NSInteger)section{
return 6;
}
in cellForItem
if(indexpath.row == 0){
CustomCell0 *cell0 = [collectionView dequeueReusableCellWithReuseIdentifier:#"MyCell0" forIndexPath:indexPath];
return cell0;
}
else if(indexpath.row == 1){
CustomCell1 *cell1 = [collectionView dequeueReusableCellWithReuseIdentifier:#"MyCell1" forIndexPath:indexPath];
return cell1;
}
:
:
else if(indexpath.row == 4){
CustomCell4 *cell4 = [collectionView dequeueReusableCellWithReuseIdentifier:#"MyCell4" forIndexPath:indexPath];
return cell4;
}
else
{
CustomCell5 *cell5 = [collectionView dequeueReusableCellWithReuseIdentifier:#"MyCell5" forIndexPath:indexPath];
return cell5;
}
You still need switch-case or if-else to specify which cell you want to load but these are some change that you can update to make you code shorter.
Move registers to viewDidLoad, you only need to call it one time:
-(void)viewDidLoad {
[super viewDidLoad];
[collection registerNib:[UINib nibWithNibName:#"CCollectionCell" bundle:nil] forCellWithReuseIdentifier:#"board"];
}
break will never be called so you can remove it too.
I'm working with Xcode 6.1.1, and I have a table view controller with static cells having 4 sections.
Section 0: contains two rows, each with 2 labels
Section 1: contains 7 image views
Section 2: contains 1 row with 1 label
Section 3: contains a variable number or rows each containing 2 image
views
I want to load all cells in the table view controller with data.
I gave each different row a reuse identifier (5 reuse identifiers in total), and I also created a class for each of the different kind of cells (5 classes)
I created outlets in the classes, and linked them in the storyboard each to its label/image view.
However I don't know how to proceed next.
If I implement the table view data source functions, I'm getting the correct number of cells, however they are all blank.
Here's how I'm creating the cells:
-(UITableViewCell*)tableView:(UITableView*)tableView cellForRowAtIndexPath:(NSIndexPath*)indexPath {
if (indexPath.section == 0 && indexPath.row == 0) {
static NSString *CellIdentifier = #"MyCell1";
MyTableViewCell1 *cell = (MyTableViewCell1*)[tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil) {
cell = [[MyTableViewCell1 alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier];
}
} else {
//create other cells here
}
cell.label1.text=#"testing 123";
return cell;
}
However, I'm always getting cells with default style (my labels or image views are not appearing)
What am I missing?? What code should I write in the custom table view cell classes?
EDIT: After gavin's suggestion, I modified the delegate function to use the dequeueReusableCellWithIdentifier:forIndexPath
I also added: [self.tableView registerClass:[MyTableViewCell1 class] forCellReuseIdentifier:#"MyCell1"] to my viewdidload method.
Here's my final code:
- (void)viewDidLoad {
[super viewDidLoad];
[self.tableView registerClass:[MyTableViewCell1 class] forCellReuseIdentifier:#"MyCell1"];
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
if (section == 3 ) {
return 1;
} else {
return [super tableView:tableView numberOfRowsInSection:section];
}
}
-(UITableViewCell*)tableView:(UITableView*)tableView cellForRowAtIndexPath:(NSIndexPath*)indexPath
{
if (indexPath.section == 3) {
// make dynamic row's cell
static NSString *CellIdentifier = #"MyCell1";
MyTableViewCell1 *cell = (MyTableViewCell1*) [tableView dequeueReusableCellWithIdentifier:CellIdentifier forIndexPath:indexPath];
[cell configureCellWithValues:#"17" andV2:#"13"];
return cell;
} else {
return [super tableView:tableView cellForRowAtIndexPath:indexPath];
}
}
- (void)tableView:(UITableView *)tableView willDisplayCell:(UITableViewCell *)cell forRowAtIndexPath:(NSIndexPath *)indexPath {
if (indexPath.section == 3) {
MyTableViewCell1 *c = (MyTableViewCell1 *) cell;
NSLog(#"willdisplay cell with values %#, %#",c.i1, c.i2);
[c.image1 setImage:[UIImage imageNamed:#"2"]];
}
}
And here's my custom cell's class:
#implementation MyTableViewCell1
- (void)awakeFromNib {
// Initialization code
}
- (void)setSelected:(BOOL)selected animated:(BOOL)animated {
[super setSelected:selected animated:animated];
// Configure the view for the selected state
}
- (void) configureCellWithValues: (NSString*) v1 andV2:(NSString*) v2 {
self.i1=v1;
self.i2=v2;
self.image1.image = [UIImage imageNamed:v1];
self.image2.image = [UIImage imageNamed:v2];
}
#end
The cells in section 3 are still not showing the images (not even the imageviews)
Look like you're using the old method of tableView reusable cell dequeueing - the new function accepts an indexPath as well as the cell identifier; it also now guarantees to return a cell (so no need for a nil check).
Here's your delegate function cleaned up:
-(UITableViewCell*)tableView:(UITableView*)tableView cellForRowAtIndexPath:(NSIndexPath*)indexPath {
if (indexPath.section == 0 && indexPath.row == 0) {
static NSString *CellIdentifier = #"MyCell1";
MyTableViewCell1 *cell = (MyTableViewCell1*)[tableView dequeueReusableCellWithIdentifier:CellIdentifier forIndexPath:indexPath];
} else {
//create other cells here
}
cell.label1.text=#"testing 123";
return cell;
}
Another tip would be to encapsulate your setting of the label values into each individual cell subclass, e.g. add a method called configure to MyTableViewCell1 that sets the label values to what you want displayed.
It seems that we can't generate custom static cells and try to access their outlets and change them (because their static) please correct me if i'm wrong because I couldn't access them at all.
I've solved my Problem by changing the TableView Type to Dynamic Cells, i didn't put any prototype cells in the tableview and I have created 3 different Cell Classes (with their nibs)
I have registered the nib files with the tableview by adding this to the viewdidload method:
[self.tableView registerNib:[UINib nibWithNibName:#"MyCellType1" bundle:nil] forCellReuseIdentifier:#"CellType1"];
[self.tableView registerNib:[UINib nibWithNibName:#"MyCellType2" bundle:nil] forCellReuseIdentifier:#"CellType2"];
[self.tableView registerNib:[UINib nibWithNibName:#"MyCellType3" bundle:nil] forCellReuseIdentifier:#"CellType3"];
then i fully customized my tableview methods:
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
// Return the number of rows in the section.
switch (section) {
case 0:
return 2;
break;
case 1:
return 1;
case 2:
return [self.myarray count];
default:
break;
}
return 0;
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
switch (indexPath.section) {
case 0: {
MyCellType1 *cell = (MyCellType1 *) [tableView dequeueReusableCellWithIdentifier:#"CellType1" forIndexPath:indexPath];
//this section always has 2 rows
if (indexPath.row==0) {
cell.lblTitle.text = #"ID";
cell.lblValue.text = [NSString stringWithFormat:#"%i",1277];
} else {
cell.lblTitle.text = #"Date";
cell.lblValue.text = #"02/03/2015";
}
return cell;
}
break;
case 1: {
MyCellType2 *cell = (MyCellType2 *)[tableView dequeueReusableCellWithIdentifier:#"CellType2" forIndexPath:indexPath];
cell.image1.image = [UIImage imageNamed:#"3"];
cell.image2.image = [UIImage imageNamed:#"4"];
return cell;
}
case 2: {
MyCellType3 *cell = (MyCellType3 *)[tableView dequeueReusableCellWithIdentifier:#"CellType3" forIndexPath:indexPath];
cell.lblName.text = #"New Row";
return cell;
}
default:
break;
}
return nil;
}
I'm developing an application on iOS targeting iOS 7.0 and later.
Now, my question is that how to reload the rows of a UITableView which are visible on screen. I'm using dynamic cells.
Actually while selecting an option I'm changing some colors like title color of each cell but those cells which are already loaded on screen are not changed and if I'm loading whole table then its taking a long time.
Waiting for your kind reply.
Code
//on clicking this button color is updating
- (IBAction)btnDone:(id)sender {
appDel.selectedMood=_moodDetView.str;
appDel.barColor=_moodDetView.backgroundColor;
self.navigationController.navigationBar.barTintColor = _moodDetView.backgroundColor;
//[self.mainTblView reloadData];
[self.menuView setBackgroundColor:appDel.barColor];
[_moodDetView setHidden:YES];
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
//For menu contents
if (tableView.tag==2) {
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:#"Cell"];
if (cell == nil) {
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:#"Cell"];
cell.textLabel.textColor = [UIColor whiteColor];
cell.textLabel.font = [UIFont fontWithName:#"Futura" size:14.0];
cell.textLabel.textAlignment = NSTextAlignmentCenter;
cell.backgroundColor = [UIColor clearColor];
}
switch (indexPath.row) {
case 0:
{
cell.textLabel.text=#"Select Mood";
}
break;
case 1:
{
cell.textLabel.text=#"Search by Author";
}
break;
case 2:
{
cell.textLabel.text=#"Search by Category";
}
break;
case 3:
{
cell.textLabel.text=#"Favorites";
}
break;
case 4:
{
cell.textLabel.text=#"Feeds";
}
break;
default:
break;
}
return cell;
}
//for main table
else{
// Configure the cell...
static NSString *CellIdentifier = #"Cell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier forIndexPath:indexPath];
FeedCustomCell* CELL=( FeedCustomCell *)cell;
CELL.cellImageView.layer.cornerRadius=CELL.cellImageView.frame.size.width/2;
CELL.cellImageView.clipsToBounds=YES;
CELL.gesRec=[[CustomTapGestureRecognizer alloc]initWithTarget:self action:#selector(authorBtnTouched:)];
[CELL.lblAuthName setTextAlignment:NSTextAlignmentJustified];
[CELL.lblAuthName setTextColor:[AppDelegate invertColor:appDel.barColor]];
NSString * str=[NSString stringWithFormat:#"%#",[[dataArray objectAtIndex:indexPath.row] objectForKey:#"authorId"]];
UIImage * img=[UIImage imageNamed:str];
CELL.cellImageView.image=img?img:[UIImage imageNamed:#"n3"];
[CELL.lblAuthName addGestureRecognizer:CELL.gesRec];
CELL.gesRec.authorImage=CELL.cellImageView.image;
NSString * authName=[[dataArray objectAtIndex:indexPath.row] objectForKey:#"authorName"];
[CELL.lblAuthName setText:authName];
[CELL.gesRec setAuthorId:(int)str.integerValue];
[CELL.gesRec setAuthorName:authName];
[CELL.txtViewQuote setTextColor:appDel.barColor];
CELL.txtViewQuote.text=[[dataArray objectAtIndex:indexPath.row] objectForKey:#"quoteTxt"];
CGSize sizeThatShouldFitTheContent = [CELL.txtViewQuote sizeThatFits:CELL.txtViewQuote.frame.size];
CELL.heightConstraintOfTxtView.constant = sizeThatShouldFitTheContent.height;
[CELL.contentView sizeToFit];
return CELL;
}
}
regards:
Syed Meesum Ali
Junior Software Developer
The simplest possible way to do it would be:
[myTable reloadRowsAtIndexPaths:myTable.indexPathsForVisibleRows withRowAnimation:UITableViewRowAnimationAutomatic];
However since you are looking for a more optimized way, The following would be better:
On button click, in the target method, iterate over visible cells, and make relevant changes in each cell.
- (IBAction)btnDone:(id)sender {
for (UITableViewCell* cell in yourTable.visibleCells) {
if ([cell isKindOfClass:[FeedCustomCell class]]) {
[((FeedCustomCell*)cell).lblAuthName setTextColor:[AppDelegate invertColor:appDel.barColor]];
}
}
}
This should be way faster that reloading (drawing) all visible cells.
ALSO, a word of advice. Use different reuseIdentifers for different types of cells, or your table might cause app crashes.
If you implement custom cell subclassing UITableViewCell, you can implement prepareForReuse method. You can reset some properties example, alpha, selection state in that method.
I am using the following 2 methods to return a custom cell:
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
NSString *key = [self keyForIndexPath:indexPath];
UITableViewCell *cell;
if ([key isEqualToString:DoneButtonCellKey]) {
cell = [self [self doneButtonCellForIndexPath:indexPath];
return cell;
} else {
//code to return default cell...
}
}
Then:
- (DoneButtonCell *)doneButtonCellForIndexPath: (NSIndexPath *)indexPath {
DoneButtonCell *cell = [self.tableView dequeueReusableCellWithIdentifier:DoneButtonCellIdentifier forIndexPath:indexPath];
return cell;
}
What is the correct init method to use with the cell here so I can change some properties of the cell when it is initialized?
EDIT: I found the problem, as the init/awakeFromNib methods were not being called for me. I tracked down the error and it was that I had not changed the "Custom Class" from UITableViewCell to my custom class. Now awakeFromNib AND initWithCoder work as described below.
You can do your changes inside the DoneButtonCell's class, either in the
- (void)awakeFromNib
{
.. essential to call super ..
super.awakeFromNib()
//Changes done directly here, we have an object
}
Or the initWithCoder: method:
-(id)initWithCoder:(NSCoder*)aDecoder
{
self = [super initWithCoder:aDecoder];
if(self)
{
//Changes here after init'ing self
}
return self;
}
If you're using Swift, remember the easy way to ensure a view is initialized when it is created is to use the didSet method. For example, to make a UIImageView into a round shape you could add code like this:
#IBOutlet weak var profileImageView: UIImageView! {
didSet {
// Make the profile icon circle.
profileImageView.layer.cornerRadius = self.profileImageView.frame.size.width / 2
profileImageView.clipsToBounds = true
}
}
This is how I am initialising custom cells
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *simpleTableIdentifier = #"FileTableViewCell";
FileTableViewCell *cell = (FileTableViewCell *)[tableView dequeueReusableCellWithIdentifier:simpleTableIdentifier];
if (cell == nil)
{
NSArray *nib = [[NSBundle mainBundle] loadNibNamed:#"FileTableViewCell" owner:self options:nil];
cell = [nib objectAtIndex:0];
}
// Configure the cell here...
// Configure the cell.
FileRepresentation* fileRepresentation = _fileList[indexPath.row];
cell.textLabel.text = [self userFilename:[fileRepresentation.fileName stringByDeletingPathExtension]];
cell.detailTextLabel.text = [fileRepresentation modifiedDate];
cell.accessoryView=nil;
cell.accessoryType = UITableViewCellAccessoryDisclosureIndicator;
[cell.progressIndicator setHidden:YES];
cell.imageView.image = [UIImage imageNamed:_fileImageName];
// Disable any user interaction while processing a request
if (_fileIsOpen || _creatingDocument || _deletingDocument) {
cell.selectionStyle = UITableViewCellSelectionStyleNone;
cell.textLabel.textColor = [UIColor grayColor];
} else {
cell.textLabel.textColor = [UIColor blackColor];
cell.selectionStyle = UITableViewCellSelectionStyleDefault;
}
}
First try to dequeue a cell if possible using dequeueReusableCellWithIdentifier method of UITableView.
If cell is not available (nil) use [[NSBundle mainBundle] loadNibNamed:#"<#your custom cell nib name#>" owner:nil options:nil][0] to initialize it.
In your custom cell's .m file, implement initWithCoder: initializer for custom initialization code:
- (id)initWithCoder:(NSCoder *)aDecoder {
self = [super initWithCoder:aDecoder];
//your custom initialization code
return self;
}
This is the designated initializer that is called when any view is loaded from a nib with loadNibNamed, like a custom table view cell.
In viewDidLoad I have:
[self.tableView registerNib:[UINib nibWithNibName:#"TypeOneCell" bundle:[NSBundle mainBundle]]
forCellReuseIdentifier:#"CustomCellOne"];
and cellForRowAtIndexPath:
TypeOneCell *cell;
cell = [tableView dequeueReusableCellWithIdentifier:#"CustomCellOne"];
return cell;
I want to use the same UITableViewController class for all the tables I push/pop. So I'll probably create an enumerated type and a variable for it. So then I'd check which type the view controller is and then make my adjustments accordingly. My question is how I would go about doing this in the same way as above. Is it a matter of (viewDidLoad):
switch (self.theControllerType) {
case CPTypeOne:
[self.tableView registerNib:[UINib nibWithNibName:#"TypeOneCell" bundle:[NSBundle mainBundle]]
forCellReuseIdentifier:#"CustomCellOne"];
break;
case CPTypeTwo:
[self.tableView registerNib:[UINib nibWithNibName:#"TypeTwoCell" bundle:[NSBundle mainBundle]]
forCellReuseIdentifier:#"CustomCellTwo"];
break;
default:
break;
}
and then (cellForRowAtIndexPath):
switch (self.theControllerType) {
case CPTypeOne {
TypeOneCell *cell;
cell = [tableView dequeueReusableCellWithIdentifier:#"CustomCellOne"];
return cell;
break;
case CPTypeTwo {
TypeOneCell *cell;
cell = [tableView dequeueReusableCellWithIdentifier:#"CustomCellTwo"];
return cell;
break;
default:
break;
}
Or is this the wrong approach? Is there a more efficient way of doing this?
Remove the switch condition in the viewDidLoad method and everything will work fine.