This works perfect if I return just 1 row of cells.
But if I put more than 1 I get the error message: "index 1 beyond bounds [0 .. 0]"
I have made a xib file that has one table cell with a unique design and I just want to use that over and over only changing some labels. Am I going about this the wrong way?
- (void)viewDidLoad
{
[super viewDidLoad];
// Uncomment the following line to preserve selection between presentations.
// self.clearsSelectionOnViewWillAppear = NO;
// Uncomment the following line to display an Edit button in the navigation bar for this view controller.
// self.navigationItem.rightBarButtonItem = self.editButtonItem;
}
- (void)didReceiveMemoryWarning
{
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
#pragma mark - Table view data source
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
{
// Return the number of sections.
return 1;
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
// Return the number of rows in the section.
return 2;
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *simpleTableIdentifier = #"Cell";
SectionCell *cell = [tableView dequeueReusableCellWithIdentifier:simpleTableIdentifier];
if (cell == nil)
{
NSArray * nib = [[NSBundle mainBundle] loadNibNamed:#"ButtonCell" owner:self options:nil];
cell = [[SectionCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:#"Cell"];
cell = (SectionCell *)[nib objectAtIndex:0];
}
cell.backgroundView.layer.masksToBounds = YES;
cell.backgroundView.layer.cornerRadius = 20.0;
cell.name.text=#"Cell Test";
tableView.backgroundView = nil;
tableView.backgroundColor = [UIColor clearColor];
return cell;
}
/*
// Override to support conditional editing of the table view.
- (BOOL)tableView:(UITableView *)tableView canEditRowAtIndexPath:(NSIndexPath *)indexPath
{
// Return NO if you do not want the specified item to be editable.
return YES;
}
*/
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
{
return 78;
}
Change to this code snipped:
if (cell == nil)
cell = [[[SectionCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:simpleTableIdentifier] autorelease];
and remove your NSBundle logic as it is no longer necessary since you are instantiating the cell object yourself.
Example:
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *simpleTableIdentifier = #"Cell";
SectionCell *cell = [tableView dequeueReusableCellWithIdentifier:simpleTableIdentifier];
if (cell == nil)
cell = [[[SectionCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:simpleTableIdentifier ] autorelease];
cell.backgroundView.layer.masksToBounds = YES;
cell.backgroundView.layer.cornerRadius = 20.0;
cell.name.text=#"Cell Test";
tableView.backgroundView = nil;
tableView.backgroundColor = [UIColor clearColor];
return cell;
}
Tip:
It isn't necessary to continuously set your tableview backgrounds the way you do. You can set it when your object is first loaded.
Instead of using :
cell = [nib objectAtIndex:indexPath.row];
use:
if (cell == nil) {
NSArray * nib = [[NSBundle mainBundle] loadNibNamed:#"ButtonCell" owner:self options:nil];
cell = (SectionCell *)[nib objectAtIndex:0];
}
Because your nib probably has only one object i.e your custom table view cell.
PS: Assuming you have a xib named "ButtonCell" having a single custom view with its custom class set to "SectionCell"
Found the answer. I had to not use static for the table view and use dynamic prototype. The only downside is I couldn't use the custom xib cell and had to modify the default cell to look as close as possible to my static cell.
Related
I Have a issue regarding accessing cell label outside of cellForRowAtIndexPath. Firstly in cellForRowAtIndexPath i am hiding cell.lblempName.hidden = YES;
Below is my code :
- (void)viewDidLoad {
[super viewDidLoad];
self.tblemplist.tableFooterView=self.footerView;
}
- (UITableViewCell *)tableView:(UITableView *)aTableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *CellIdentifier = #"Cell";
EmployeeCell *cell = (EmployeeCell *) [aTableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil) {
NSArray *topLevelObjects = [[NSBundle mainBundle] loadNibNamed:#"EmployeeCell" owner:self options:nil];
for (id currentObject in topLevelObjects){
if ([currentObject isKindOfClass:[UITableViewCell class]]){
cell = (EmployeeCell *) currentObject;
cell.backgroundColor=[UIColor clearColor];
}
}
}
NSMutableDictionary *detailsdict=[empArray objectAtIndex:indexPath.row];
cell.lblTitle.text = [detailsdict objectForKey:#"empTitle"];
cell.lblItemprice.text = [detailsdict objectForKey:#"empId"];
cell.lblempName.hidden = YES;
}
And in the Footer i have added a View and placed a button. When i click the button lblempName should UnHide.
- (IBAction)btnApplyClicked:(id)sender {
// How to unHide cell.lblempName.hidden = NO;
}
please help me to find the solution. TIA
create a bool property as BOOL isEmpNameHidden;
In viewDidLoad, set isEmpNameHidden = YES;
- (UITableViewCell *)tableView:(UITableView *)aTableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
//Your existing code here
....
cell.lblempName.hidden = isEmpNameHidden;
}
then unhide based on the button tap
- (IBAction)btnApplyClicked:(id)sender {
isEmpNameHidden = NO;
[self.tblemplist reloadData]
}
EmployeeCell *cell = (EmployeeCell *)[self.tableView cellForRowAtIndexPath:indexPath];
UILabel *label = cell.lblempName;
label.hidden = NO;
But better is to modify your data, because as soon as the cell scrolls out of the view and back again the label will be visible again since it will be constructed again.
Trying to get my app to display text in its cells. Been scratching my head for a while. This is the code used to display the text but nothing appears. Any advice?
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *cellIdentifier = #"leftMenuCell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:cellIdentifier];
if (cell == nil) {
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:cellIdentifier];
}
if (indexPath.section == 0) {
NSArray *titles = #[#"Quick Glance", #"Your Home", #"Invites"];
cell.textLabel.text = titles[indexPath.row];
}
cell.backgroundColor = [UIColor clearColor];
return cell;
}
If you have not add the following code in ViewDidLoad() method, please do so.
self.tableView.dataSource = self;
self.tableView.delegate = self;
Firstly you should break this out differently so that you are not re-creating your backing store every time you are producing a cell.
More code would be required in order to ascertain exactly what the issue but at minimum you could put the following in to verify this.
#implementation ViewController {
NSArray *_titles;
}
- (void)viewDidLoad
{
[super viewDidLoad];
_titles = #[#"Quick Glance", #"Your Home", #"Invites"];
}
- (NSInteger)tableView:(UITableView*)tableView numberOfRowsInSection:(NSInteger)section
{
return [_titles count];
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *cellIdentifier = #"leftMenuCell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:cellIdentifier];
if (cell == nil) {
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:cellIdentifier];
}
cell.textLabel.text = titles[indexPath.row];
cell.backgroundColor = [UIColor clearColor];
return cell;
}
This is the bare minimum you will need above in order to show some information in the tableview
Now the question is are you using a UITableViewController where it already has set the dataSource and delegate methods or are you using a UIViewController where the dataSource and delegate have not been set (either in code or through XIB or Storyboard)?
If you do not have the delegates set up you need to set them up either through the storyboard or through the code, and if through code and using UIViewController make sure you have a reference to the UITableView otherwise you will not be able to set the datasource.
I currently have a tableView with custom cells that I've called AMPFeedbackTableViewCell. The cells load up perfectly fine.
Here is the code:
-(UITableViewCell*) tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
//UITableViewCell* cell = [tableView dequeueReusableCellWithIdentifier:#"feedbackCell"];
AMPFeedbackTableViewCell* cell = (AMPFeedbackTableViewCell*) [tableView dequeueReusableCellWithIdentifier:#"feedbackCell"];
if (cell == nil)
{
cell = [[AMPFeedbackTableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:#"feedbackCell"];
cell.currentFeedback = [[AMPFeedback alloc] init];
cell.currentFeedback = [_feedbackArray objectAtIndex:indexPath.row];
NSArray *nib = [[NSBundle mainBundle] loadNibNamed:#"FeedbackTableCell" owner:self options:nil];
cell = [nib objectAtIndex:0];
}
I'm trying to pass something to the cell before it starts like in this case it's _currentFeedback. The custom cell has a AMPFeedback item and I want it to set it before it loads. So I can use it like this : (NOTE: This is in AMPFeedbackTableViewCell
- (void)awakeFromNib
{
// Initialization code
if (_currentFeedback != nil)
[self loadImages];
}
However, _currentFeedback is always nil. Is there a way I can pass it over then call awakeFromNib?
Thanks in advance
If you are not insist on doing this inside awakefromNib, there's another way (and maybe better) to do this:
in AMPFeedbackTableViewCell.h
#property (strong) AMPFeedBack *currentFeedback;
in AMPFeedbackTableViewCell.m
#synthesize currentFeedback = _currentFeedback;
- (void)setCurrentFeedback:(AMPFeedback *)feedback {
if (feedback==nil) return;
_currentFeedback = feedback;
[self loadImages];
}
and then we can trigger it directly in main code:
-(UITableViewCell*) tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
AMPFeedbackTableViewCell* cell = (AMPFeedbackTableViewCell*) [tableView dequeueReusableCellWithIdentifier:#"feedbackCell"];
if (cell == nil) {
cell = [[AMPFeedbackTableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:#"feedbackCell"];
}
cell.currentFeedback = [_feedbackArray objectAtIndex:indexPath.row];
Hope it helps.
You can do initialization and loading of data in the following method of custom uitableview cell
-(id)initWithStyle:(UITableViewCellStyle)style reuseIdentifier:(NSString *)reuseIdentifier
{
self = [super initWithStyle:style reuseIdentifier:reuseIdentifier];
if (self) {
// Initialization code
}
return self;
}
and you can load customcell in your tableview
-(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *eventListCell = #"EventListCell";
EventListCell *cell = (EventListCell *)[tableView dequeueReusableCellWithIdentifier:eventListCell];
if (cell == nil)
{
cell = (EventListCell*)[[[NSBundle mainBundle] loadNibNamed:#"EventListCell" owner:self options:nil] objectAtIndex:0];
// here you can access the custom class public variable to set data .
}
}
This question already has answers here:
2 different types of custom UITableViewCells in UITableView
(3 answers)
Closed 9 years ago.
I'm having an issue and would like to know if what I am trying to do is even possible.
I have a ViewController that has a UITableView as a subview. I then loaded a custom cell and it worked fine. However, I needed another custom cell in the same tableview - this second cell has a separate nib as well.
Is this possible?
Two different custom cells in on section in a UITableView?
I did try something like this:
- (UITableViewCell*)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *CellIdentifier1 = #"ContentCell";
static NSString *CellIdentifier2 = #"SpaceCell";
// Space Cell
if (indexPath.row== 0) {
CellSpace *cell = (CellSpace *) [tableViewdequeueReusableCellWithIdentifier:CellIdentifier2];
return cell;
}
// Content cell
else {
CellView *cell = (CellView *)[tableView dequeueReusableCellWithIdentifier:CellIdentifier1];
// Configure cell
return cell;
}
}
However it seems the else statement is never fired and I normally get a crash saying the method returned nil.
UPDATE
I used the advice and code here and came up with this:
#pragma mark - UITableView Delegate Methods
-(CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
{
return 160;
}
-(NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
return 22;
}
-(NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
{
return 1;
}
-(UITableViewCell *) tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath{
static NSString *CellIdentifier1 = #"UsernameCell";
static NSString *CellIdentifier2 = #"PasswordCell";
if(indexPath.row == 0) {
BBUsernameRegistrationCell *cell = (BBUsernameRegistrationCell *)[tableView dequeueReusableCellWithIdentifier:CellIdentifier1];
if(cell == nil) {
NSArray *nib = [[NSBundle mainBundle] loadNibNamed:CellIdentifier1 owner:self options:nil]; // set properties
cell = nib[0];
}
// set properties
return cell;
}
// Content cell
else {
BBPasswordTableViewCell *cell = (BBPasswordTableViewCell *)[tableView dequeueReusableCellWithIdentifier:CellIdentifier2];
if(cell == nil) {
NSArray *nib = [[NSBundle mainBundle] loadNibNamed:CellIdentifier2 owner:self options:nil]; // set properties
cell = nib[0];
}
// set properties
return cell;
}
}
However I only see the first Cell in my tableview. If I switch the cells around the second one loads. But not both at the same time. Does anyone have any idea why?
Yes, it is possible..
- (UITableViewCell*)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *CellIdentifier1 = #"ContentCell";
static NSString *CellIdentifier2 = #"SpaceCell";
// Space Cell
if (indexPath.row== 0) {
CellSpace *cell = (CellSpace *)[tableView dequeueReusableCellWithIdentifier:CellIdentifier2];
if(cell == nil) {
cell = [[CellSpace alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier1];
// set properties
}
// set properties
return cell;
}
// Content cell
else {
CellView *cell = (CellView *)[tableView dequeueReusableCellWithIdentifier:CellIdentifier2];
if(cell == nil) {
cell = [[CellView alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier2];
// set properties
}
// set properties
return cell;
}
}
in your custom cell, do something like this in initWithStyle method:
- (id)initWithStyle:(UITableViewCellStyle)style reuseIdentifier:(NSString *)reuseIdentifier
{
NSArray *topLevelObjects = [[NSBundle mainBundle] loadNibNamed:#"CellView" owner:self options:nil];
for (id currentObj in topLevelObjects ) {
if ([currentObj isKindOfClass:[CellView class]]) {
self = (CellView*) currentObj;
}
}
return self;
}
Yes it is possible. But before use this dequeueReusableCellWithIdentifier:. Just register your cell and corresponding nib files.
code as..
-(void)initiateCellRegisteration
{
static NSString *CellIdentifier1 = #"ContentCell";
static NSString *CellIdentifier2 = #"SpaceCell";
[self.tableView registerClass:[ContentCell class] forCellReuseIdentifier:CellIdentifier2];
[self.tableView registerNib:[UINib nibWithNibName:CellIdentifier2 bundle:nil] forCellReuseIdentifier:CellIdentifier2];
[self.tableView registerClass:[SpaceCell class] forCellReuseIdentifier:CellIdentifier1];
[self.tableView registerNib:[UINib nibWithNibName:CellIdentifier1 bundle:nil] forCellReuseIdentifier:CellIdentifier1];
}
Call this method in viewDidLoad
If you are using the cell nib then you need little tricky way to get your cell nib like
static NSString *CellIdentifier = #"ProductCell";
IVProductCell *cell = (IVProductCell*)[tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil) {
NSArray* objects = [[NSBundle mainBundle] loadNibNamed:#"IVProductCell" owner:nil options:nil];
for (id currentObject in objects) {
if ([currentObject isKindOfClass:[IVProductCell class]]){
cell = (IVProductCell*) currentObject;
}
}
}
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.