Problem in displaying custom UITableViewCell - iphone

I have a tableview displaying data using a custom UITableViewCell(say cell1). On touch of a row, I change the custom cell to another custom UITableViewCell(say cell2). Also I increase the size of row of the selected cell to accomodate, more items of cell2.
My problem is that the approach works fine when the number of rows in table view is less. When the number of rows increses, the rows expand on touching, but the data displayed is same as that of cell1. Cell2 doesn't seem to be loaded at all.
Looking forward for a reply soon....Thanks in advance.

I am posting my code....please let me know if there is a problem in that.
My cellForRowAtIndexPath looks like this:
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
if(indexPath == selectedCellIndexPath)
{
static NSString *Identifier1 = #"Identifier1";
Identifier1 = #"cell2";
CustomCellController1 *cell = (CustomCellController1 *)[tableView dequeueReusableCellWithIdentifier:Identifier1];
if(cell == nil) {
[[NSBundle mainBundle] loadNibNamed:#"CustomCellController1View" owner:self options:nil];
cell = rowTwoObject;
}
[cell setText:[test1Array objectAtIndex:indexPath.row]];
return cell;
}
else {
static NSString *Identifier2 = #"Identifier2";
Identifier2 = #"cell1";
CustomCellController1 *cell = (CustomCellController1 *)[tableView dequeueReusableCellWithIdentifier:Identifier2];
if(cell == nil) {
[[NSBundle mainBundle] loadNibNamed:#"CustomCellController1View" owner:self options:nil];
cell = rowOneObject;
}
[cell setText1:[temp1Array objectAtIndex:indexPath.row]];
[cell setText2:[temp2Array objectAtIndex:indexPath.row]];
return cell;
}
}
didSelectRowAtIndexPath looks like this:
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
selectedCellIndexPath = indexPath;
[tableView reloadData];
}
heightForRowAtIndexPath looks like this:
-(CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath {
if(selectedCellIndexPath != nil
&& [selectedCellIndexPath compare:indexPath] == NSOrderedSame)
return 110;
return 60;

Related

"Load more.." on tableView with custom cells - cell reusing is causing me some issues

I'm trying to implement "Load more..." on a tableView. I've done it, but I don't know if it's efficient.
The thing is that I have custom cells, and if I do like this:
-(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *cellIdentifier = #"Cell";
ArticlesCell *cell = [tableView dequeueReusableCellWithIdentifier:cellIdentifier];
if (cell==nil)
{
NSArray *nib = [[NSBundle mainBundle] loadNibNamed:#"ArticlesCell" owner:self options:NULL];
cell = (ArticlesCell *) [nib objectAtIndex:0];
cell.accessoryType = UITableViewCellAccessoryDisclosureIndicator;
}
tableView.backgroundColor = cell.backgroundColor;
if (indexPath.row <= (self.bookmarks.count - 1)) {
[self configureCell:cell atIndexPath:indexPath];
}else{
cell.textLabel.text = #"Load more...";
}
return cell;
}
It works great but what happens is it's reusing the cells, and if I scroll, every fifth cell (this is height 77.0) will have the label "Load more...", but actually do it's job as normal.
I found this workaround, but I don't know is it good and efficient.
Here it is:
-(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *cellIdentifier = #"Cell";
if (indexPath.row <= (self.bookmarks.count - 1)) {
ArticlesCell *cell = [tableView dequeueReusableCellWithIdentifier:cellIdentifier];
if (cell==nil)
{
NSArray *nib = [[NSBundle mainBundle] loadNibNamed:#"ArticlesCell" owner:self options:NULL];
cell = (ArticlesCell *) [nib objectAtIndex:0];
cell.accessoryType = UITableViewCellAccessoryDisclosureIndicator;
}
tableView.backgroundColor = cell.backgroundColor;
[self configureCell:cell atIndexPath:indexPath];
return cell;
}else{
UITableViewCell *cell = [[UITableViewCell alloc] init];
cell.textLabel.text = #"Load more...";
return cell;
}
}
As you can see I'm making the "Load more..." cell a simple UITableViewCell, and not reusing it, since it's only one. Is this good approach? Can you advice me in something better?
Thank you!
Another approach would be to use 2 different cell identifiers, one to identify and reuse (once initially created) an ArticlesCell and another to identify and reuse (once initially created) a "Load more..." UITableViewCell. At least then you will only create the "Load more..." UITableViewCell once rather than every time it scrolls into view.
static NSString *ArticleCellIdentifier = #"ArticleCell";
static NSString *LoadMoreCellIdentifier = #"LoadMoreCell";
The LazyTableImages Apple iOS sample project uses a similar approach (see the Classes/ RootViewController.m).
When you are click on loadmore button then increase the number of rows and reload the tableview . i.e in the method numberofrowsinsection.Let me know if you need any more

Loading a UITableViewCell subclass using a XIB file

I am having trouble getting my CustomTableViewCell, a subclass of UITableViewCell to appear in my table view.
I am using a xib to represent that cell, but I am assuming that the code for the data source delegate doesn't change. I made sure to set an identical reuse identifier inside the table view cell XIB.
I isolated the problem to the fact that the datasource method that returns the table cell isn't working correctly, here it is:
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *CellIdentifier = #"Cell";
CustomTableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
DataObject *foo = [self.dataArray objectAtIndex:indexPath.row];
if (cell == nil)
{
cell = [[CustomTableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier];
}
[[cell overview] setText:foo.overview];
[[cell price] setText:foo.price];
NSLog(#"cell initialized, description text is %#",cell.overview.text);
return cell;
}
Not sure why this isn't working, but that last log statement always prints a (null) at the end, and yes I did verify that the overview property of the data object has a valid string in it. Same thing for price.
1) Make your Custom cell class separate
2) XIB : File Owner class change to NSObject
3) XIB : UITableViewCell change to MyTableViewCell
4) Where you want to add inside table view code as
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath{
static NSString *CellIdentifier = #"MyCell";
MyTableViewCell *cell = (MyTableViewCell*) [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil) {
NSArray *arrayCellXib = [[NSBundle mainBundle] loadNibNamed:#"MyTableViewCell"
owner:self
options:nil];
if (indexPath.row == 0) {
// first table cell
cell = [arrayCellXib objectAtIndex:0]; // *
......
}else {
cell = [arrayCellXib objectAtIndex:1]; // *
}
...
}
return cell;
}
Object at index 0,1 ... are index for which order you make MyTableViewCell in xib, if you want to have more than one custom cell. means in a MyTableViewCell class u make unlimited custom cell and use according to requirement.
Normally, just make ONE custom cell in the XIB and do exactly this:
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
int thisRow = indexPath.row;
NSString *exampleText = [yourData objectAtIndex:thisRow];
static NSString *CellID = #"cu5";
FancyCell *cell =
(FancyCell *)[tableView dequeueReusableCellWithIdentifier:CellID];
if (cell == nil)
{
NSArray *cellTeam =
[[NSBundle mainBundle] loadNibNamed:#"FancyCell"
owner:self options:nil];
cell = [cellTeam objectAtIndex:0];
}
[cell someFunction:exampleText];
[cell.someLabel setText:exampleText];
return cell;
}
Hoping may help u :)
In .h file, you write it.
IBOulet CustomTableViewCell *tableCell;
and connect to File's Owner in CustomTableViewCell's .xib file.
You modify this in (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
if (cell == nil)
{
[[NSBundle mainBundle] loadNibNamed:#"CustomTableViewCell" owner:self options:nil];
cell = tableCell;
}
I think it will be helpful to you.

cellForRowAtIndexPath returning custom cell?

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
// ...
PlanetTableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:#"PlanetCell_ID"];
return cell;
}
If your creating a custom UITableViewCell (in this case PlanetTableViewCell) is it acceptable to return that object via a method returning (UITableViewCell *), or is there something else I should be doing?
If your creating a custom UITableViewCell (in this case PlanetTableViewCell) is it acceptable to return that object via a method returning (UITableView *), or is there something else I should be doing?
You possibly meant:
to return that object via a method returning (UITableViewCell*),
If so, then it is perfectly legal and reasonable.
Indeed, your PlanetTableViewCell being derived from UITableViewCell, all instances of PlanetTableViewCell are also of the type UITableViewCell (is-a relationship in OOP).
Yes, this is the correct way to return the cell.
But you should also be checking to see if your "dequeue" is returning a valid cell object. If not, you'll need to create one.
This method is also where you should be configuring your cell with title, accessories, etc.
Sample code:
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
// ...
PlanetTableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:#"PlanetCell_ID"];
if (cell == nil) {
cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier] autorelease];
}
cell.titleLabel.text = #"Cell Title";
cell.accessoryType = UITableViewCellAccessoryDisclosureIndicator;
return cell;
}
Using custom cell
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *simpleTableIdentifier;
if (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPad)
{
simpleTableIdentifier = #"dashboard_logintimeCell_ipad";
}
else
{
simpleTableIdentifier = #"dashboard_logintimeCell";
}
dashboard_logintimeCell *cell = (dashboard_logintimeCell *)[tableView dequeueReusableCellWithIdentifier:simpleTableIdentifier];
if (cell == nil)
{
NSArray *nib =[[NSBundle mainBundle]loadNibNamed:simpleTableIdentifier owner:self options:nil];
cell = [nib objectAtIndex:0];
}
/*here you cell object get
like
cell.lable.text=#"yourlabeltext";
*/
cell.backgroundColor=[UIColor clearColor];
return cell;
}

How do you use custom UITableViewCell's effectively?

I am currently making a custom UITableView cell as shown below.
The custom UITableViewCell is in its own nib file that I am calling from another ViewController. (like so)
// RegistrationViewController.m
//Sets number of sections in the table
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
return 2;
}
// Sets the number of rows in each section.
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
return 1;
}
//Loads both Custom cells into each section
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
//Registration Cell
static NSString *CellIdentifier = #"CustomRegCell";
static NSString *CellNib = #"LogInCustomCell";
UITableViewCell *cell = (UITableViewCell *)[tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil) {
NSArray *nib = [[NSBundle mainBundle] loadNibNamed:CellNib owner:self options:nil];
cell = (UITableViewCell *)[nib objectAtIndex:0];
}
//Registration Button
static NSString *CellButtonIdentifier = #"CustomSubmitCell";
static NSString *CellButtonNib = #"LogInSubmitButton";
UITableViewCell *cellButton = (UITableViewCell *)[tableView dequeueReusableCellWithIdentifier:CellButtonIdentifier];
if (cellButton == nil) {
NSArray *nibButton = [[NSBundle mainBundle] loadNibNamed:CellButtonNib owner:self options:nil];
cellButton = (UITableViewCell *)[nibButton objectAtIndex:0];
}
if (indexPath.section == 0) {
cell.selectionStyle = UITableViewCellSelectionStyleNone; //Stops the UITableViewCell from being selectable
[self registrationControll];
//TODO: call method that controls this cell
return cell;
}
if (indexPath.section == 1) {
cellButton.selectionStyle = UITableViewCellSelectionStyleNone; //Stops the UITableViewCell from being selectable
return cellButton;
}
return nil;
}
It has four text fields that I am wanting to limit the size of the string that can be entered to five. (I'm only trying it with the first text field so far but its not even entering the textField:shouldChangeCharactersInRange:replacementString: delegate method (found this out while debugging the app) here is the code for the part I am trying to restrict the amount of characters that can be entered.
// RegistrationViewController.m
//textField:shouldChangeCharactersInRange:replacementString:
- (BOOL)textField:(UITextField *)textField shouldChangeCharactersInRange:(NSRange)range replacementString:(NSString *)string
{
int length = [regFieldOne.text length] ;
if (length >= MAXLENGTH && ![string isEqualToString:#""]) {
regFieldOne.text = [regFieldOne.text substringToIndex:MAXLENGTH];
return NO;
}
return YES;
}
I think I have limited my error to one of two things.
Maybe I haven't set everything up in interface builder correctly.
OR it has something to so with delegation... which I have a general understanding of and is why I think the issue might be here, but with such a complex file structure I'm not sure how or if this is right.
Any help, explanations, suggestions etc would be greatly appreciated.
At some point, you need to set the delegate for the textField
Since you put the delegate method in RegistrationViewController.m, you can set the delegate right after adding the cell in
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath.
As long as you are returning a subclass of UITableViewCell from LogInCustomCell.xib, you can use something like this:
LogInCustomCell *cell = (LogInCustomCell *)[tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil) {
NSArray *nib = [[NSBundle mainBundle] loadNibNamed:CellNib owner:self options:nil];
cell = (LogInCustomCell *)[nib objectAtIndex:0];
}
cell.textField1.delegate = self;
cell.textField2.delegate = self;
cell.textField3.delegate = self;
cell.textField4.delegate = self;
...
return cell;
From what I can see
You have the delegate methods in RegistrationViewController.m
But you are idnicating that CustomRegCell is the delegate, so the delegate methods should be there

Adding new rows to UITableViewCell

In my application,I will be displaying only one row on the UITableView initially. I want to increase the rows as user loads the previous row with data(an uiimage, here). As now i'm returning value 1, in numberOfRowsInSection: method, since I don't know how to implement it in the required way. Please help.
My cellForRowAtIndexPath: method is
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
static NSString *CustomCellIdentifier = #"CustomCellIdentifier";
CustomCell *cell = (CustomCell *)[tableView dequeueReusableCellWithIdentifier:CustomCellIdentifier];
if (cell == nil) {
cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CustomCellIdentifier ] autorelease];
NSArray *nib = [[NSBundle mainBundle] loadNibNamed:#"CustomCell" owner:self options:nil];
for (id currentObject in nib){
if ([currentObject isKindOfClass:[CustomCell class]]){
cell = (CustomCell *)currentObject;
cell.viewController = self;
break;
}
}
}
if (j<15){
cell.imageView.image = nil;
if (count!=0)
{
#try{
NSInteger row = [indexPath row];
cell.imageView.image = [array objectAtIndex:row];
}
#catch (NSException* ex) {
NSLog(#"doSomethingFancy failed: %#",ex);
}
}
}
cell.showsReorderControl = YES;
return cell;
[array release];
}
that if condition and count is nothing but just for checking the correct functioning of the mutable array, 'array'.
You should read this documentation: http://developer.apple.com/iphone/library/documentation/UserExperience/Conceptual/TableView_iPhone/Introduction/Introduction.html
Have a look to the related samples as well.
Note: in your code [array release] won't be called since you've got a return statement just before it.
When you reach the cellForRowAtIndexPath at a certain indexPath, it means that row is being displayed. If you reach the last row you can insert a new row into the table. To do that, you just need to increase the count that will get returned by the tableView:numberOfRowsInSection function.
I'm guessing your numberOfRowsInSection function will look something like this:
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
return section==0 ? [array count] : 0;
}
So basically, inside cellForRowAtIndexPath, add the following code:
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
...
if([indexPath row]==[array count]-1) {
[array addObject:(NEXT_IMAGE)];
}
return cell;
}
You also need to refresh the table. One way is to just call reloadData on your UITableView, but the preferred way is to call beginUpdates/insertRowsAtIndexPaths/endUpdates on the table so that you can show a nice animation of the row being inserted.