change the appearance of a single UITableViewCell based on the content - iphone

I have a problem with a UITableView with custom UITableViewCell.
The table is filled by an NSArray, and I want that if an object in this NSArray begins with - changes its appearance.
the problem is that the UITableViewCell that begins with - is changed, but also change other cells that should not change.
this is my code:
//this is the way in which change the height of the cell if the object in the array begins with -
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath {
NSString *try = [arrayTitleEs objectAtIndex:indexPath.row];
if ([[try substringToIndex:1]isEqualToString:#"-"]) {
return 45;
}
else return 160;
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
static NSString *CellIdentifier = #"CellCardioScheda";
CardioSchedaCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier forIndexPath:indexPath];
cell.titleEs.text = [arrayTitoloEs objectAtIndex:indexPath.row];
NSString *try = [arrayTitoloEs objectAtIndex:indexPath.row];
if ([[try substringToIndex:1]isEqualToString:#"-"]) {
cell.titleEs.frame = CGRectMake(0, 0, cell.frame.size.width-15, cell.frame.size.height);
}
return cell;
}
as you can see from the picture that begins with the cell - is smallest and the text is moved to the left, in the next cell is all right, but the text in the last cell is moved, but should not!
thanks to all

In cellForRowAtIndexPath you can create two different types of cells and return one or the other according to your needs:
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
UITableViewCell *firstCell = [tableView dequeueReusableCellWithIdentifier:#"firstCellID"];
if (firstCell == nil) {
firstCell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:#"firstCellID"] autorelease];
}
// Set here firstCell
UITableViewCell *secondCell = [tableView dequeueReusableCellWithIdentifier:#"secondCellID"];
if (secondCell == nil) {
secondCell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:#"secondCellID"] autorelease];
}
// Set here secondCell
if ([[try substringToIndex:1]isEqualToString:#"-"]) {
return secondCell;
} else {
return firstCell;
}
}

The problem is with the following:
if ([[try substringToIndex:1]isEqualToString:#"-"]) {
cell.titleEs.frame = CGRectMake(0, 0, cell.frame.size.width-15, cell.frame.size.height);
}
You need an else to set the frame properly if the condition isn't met. Cells get reused. Anything you do to a cell must be done for all cells.
if ([[try substringToIndex:1]isEqualToString:#"-"]) {
cell.titleEs.frame = CGRectMake(0, 0, cell.frame.size.width-15, cell.frame.size.height);
} else {
cell.titleEs.frame = CGRectMake(...); // whatever regular cells should be
}
BTW - you could replace [[try substringToIndex:1]isEqualToString:#"-"] with [try hasPrefix:#"-"].

Related

Collapse UITableViewCell to original size when another cell is clicked

This question is connected to the following question: Can you animate a height change on a UITableViewCell when selected?
I am animating the height change of the UITableViewCell explained in that question by using the following code:
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
ProductCell *cell = (ProductCell *) [tableView cellForRowAtIndexPath:indexPath];
// Deselect cell
[tableView deselectRowAtIndexPath:indexPath animated:NO];
// Toggle 'selected' state
BOOL isSelected = ![self cellIsSelected:indexPath];
// Store cell 'selected' state keyed on indexPath
NSNumber *selectedIndex = [NSNumber numberWithBool:isSelected];
[self.selectedIndexes setObject:selectedIndex forKey:indexPath];
if (isSelected) {
cell.addButton.hidden = NO;
}else {
cell.addButton.hidden = YES;
}
// This is where magic happens...
[self.theMenuListTableView beginUpdates];
[self.theMenuListTableView endUpdates];
}
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath {
// If our cell is selected, return double height
if([self cellIsSelected:indexPath]) {
return kCellHeight * 2.0;
}
// Cell isn't selected so return single height
return kCellHeight;
}
- (BOOL)cellIsSelected:(NSIndexPath *)indexPath {
NSNumber *selectedIndex = [self.selectedIndexes objectForKey:indexPath];
return selectedIndex == nil ? FALSE : [selectedIndex boolValue];
}
This is working fine, but want I want is, that when one cell is clicked and the height has been animated, and I then click on another cell, I want the first cell to contract/collapse to it's original size and the other to expand (animate the height change).
How can I do this?
When you select a cell, and it s animated, store the cell's indexPath. When you click an another cell, check is it the same cell or the indexPath is different. Write a method which will make the other animation . If you have a stored indexPath then call that new method for the cell with that stored indexPath. I hope it helps.
So i guess you are saving selected indexes in a NSDictionary object, and for every indexPath you save state (Selected/Not Selected).
What you need to do is to save only 1 cell's index, the selected one.
So, basically need the following changes :
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
ProductCell *cell = (ProductCell *) [tableView cellForRowAtIndexPath:indexPath];
// Deselect cell
[tableView deselectRowAtIndexPath:indexPath animated:NO];
if (![indexPath isEqual:selectedIndex]) {
cell.addButton.hidden = NO;
// Store cell 'selected' state keyed on indexPath
selectedIndex = indexPath;
}else {
//Click deselecting cell
selectedIndex = nil;
cell.addButton.hidden = YES;
}
// This is where magic happens...
[self.theMenuListTableView beginUpdates];
[self.theMenuListTableView endUpdates];
}
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath {
// If our cell is selected, return double height
if(selectedIndex != nil && [selectedIndex isEqual:indexPath]) {
return kCellHeight * 2.0;
}
// Cell isn't selected so return single height
return kCellHeight;
}
//- (BOOL)cellIsSelected:(NSIndexPath *)indexPath {
//
// NSNumber *selectedIndex = [self.selectedIndexes objectForKey:indexPath];
// return selectedIndex == nil ? FALSE : [selectedIndex boolValue];
//}
and add to .h file of your Controller
#property NSIndexPath * selectedIndex;
and to .m
#synthetize selectedIndex;
i could check if this code runs, so try it and see if it is the solution for you.
Maybe that helps:
- (UITableViewCell*)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath*)indexPath
{
static NSString *CellIdentifier = #"Cell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil) {
cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault
reuseIdentifier:CellIdentifier] autorelease];
}
cell.textLabel.text = [NSString stringWithFormat:#"%d",indexPath.row];
cell.selectionStyle = UITableViewCellEditingStyleNone;
return cell;
}
- (int) tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
return 3;
}
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
[tableView reloadRowsAtIndexPaths:#[indexPath] withRowAnimation:UITableViewRowAnimationMiddle];
if (indexPath.row > 0) {
NSIndexPath *path = [NSIndexPath indexPathForRow:indexPath.row - 1 inSection:indexPath.section];
[tableView reloadRowsAtIndexPaths:#[path] withRowAnimation:UITableViewRowAnimationNone];
}
}
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath {
// If our cell is selected, return double height
if([self cellIsSelected:indexPath]) {
return 40 * 2.0;
}
// Cell isn't selected so return single height
return 40;
}
- (BOOL)cellIsSelected:(NSIndexPath *)indexPath {
return (tblView.indexPathForSelectedRow.row == indexPath.row);
}

rowHeight in cellForRowAtIndexPath unchanged

I have a problem with rowHeight, which seems to be not changed ( though I do it in method heightForRow...)
-(CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath {
if(indexPath.section == 0 && indexPath.row == 0) {
return 80;
} else
return 0;
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *CellIdentifier = #"Cell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil) {
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier];
}
[cell setSelectionStyle:UITableViewCellSeparatorStyleNone];
// Configure the cell...
if(indexPath.section == 0 && indexPath.row == 0) {
NSLog(#"frame.size.height: %f rowHeight: %f", cell.frame.size.height, tableView.rowHeight);
}
return cell;
}
It says 44.0000 for both values: cell.frame.size.height and for rowHeight.
Here's how do I initialize this table in navcontroller:
DPSettingsInformations *settingsInformations = [[DPSettingsInformations alloc] initWithStyle:UITableViewStyleGrouped];
[self.navigationController pushViewController:settingsInformations animated:YES];
44 is the default height so it sounds as if you haven't set the UITableViewDelegate.
tableView:heightForRowAtIndexPath: requires the UITableViewDelegate to be set. Make sure that this is set correctly in the Nib, Storyboard or in code. Usually you set it at the same time as the UITableViewDataSource.
Example (if setting in code):
// UITableViewDataSource delegate
self.tableView.dataSource = self;
// UITableViewDelegate delegate
self.tableView.delegate = self;

EXE Bad Access when Scrolling UITableView - iPhone

I have a simple UITableView with 9 cells. When I move the table up or down by scrolling, I get EXE bad access. NSZombieMode points at the cellForRowAtIndexMethod.
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *CellIdentifier = #"Cell";
UITableViewCell *cell =
[tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil) {
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault
reuseIdentifier:CellIdentifier];
}
cell.textLabel.text = [lineArray objectAtIndex:indexPath.row];
cell.accessoryType = UITableViewCellAccessoryDisclosureIndicator;
return cell;
}
Can anyone suggest what is wrong ?
If ARC is disabled then add autorelease when you create cell
cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault
reuseIdentifier:CellIdentifier] autorelease];
This can be the reason of the leaks. Check also lineArray since it used like ivar and probably this array was released at some point.
My guess is you're trying to access an element in your lineArray that is out of bounds.
IE: indexPath.row is returning a 6 when you only have 3 elements in your lineArray.
It's occurring when you scroll down as it triggers cellForRowAtIndexPath to be called on higher number rows (rows that with indexPath.row > 3 for example)
I'll go one more step and guess that you're probably statically returning numberOfRowsForSection.
Setting it to lineArray.count should fix it.
According to my understanding :-
1) in the lineArray you have some 9 items but in the numberOfRowsInSection you are returning the rowCount more than the items in the array and so it crashes and points to ceelForRowAtIndex.
2) Here is the sample code for your understanding :-
- (void)viewDidLoad
{
[super viewDidLoad];
lineArray = [[NSMutableArray alloc]initWithObjects:#"1",#"2",#"3",#"4",#"5", nil];
tableView1 = [[UITableView alloc]init];
tableView1.delegate = self;
tableView1.dataSource = self;
tableView1 .frame =self.view.frame;
[self.view addSubview:tableView1];
}
- (void)viewDidUnload
{
[super viewDidUnload];
}
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation
{
return (interfaceOrientation != UIInterfaceOrientationPortraitUpsideDown);
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
return [lineArray count];
//return ;
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *CellIdentifier = #"Cell";
UITableViewCell *cell =
[tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil) {
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault
reuseIdentifier:CellIdentifier];
}
cell.textLabel.text = [lineArray objectAtIndex:indexPath.row];
cell.accessoryType = UITableViewCellAccessoryDisclosureIndicator;
return cell;
}
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
{
return 1;
}
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
}

uitableviewcell alternating background cell colors even for cells without data

I know how to set alternating colors to a tableviewcell, but how can I set all the visible rows to have an alternating color? For instance, right now if I only have 2 cells with data, only 2 cells will have background colors - how do I fill the backgrounds of the empty cells too?
try doing some thing like this:
(a)Add only required number of dummy rows
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
if ([UIAppDelegate.getwaitlistArray count]>=numberOfVisibleRowsOnYourScreen) {
return [UIAppDelegate.getwaitlistArray count];
}
else{
return ([UIAppDelegate.getwaitlistArray count] + numberOfVisibleRowsOnYourScreen - [UIAppDelegate.getwaitlistArray count]);
}
}
(b)Alternare your cell:
-(void)tableView:(UITableView *)tableView willDisplayCell:(UITableViewCell *)cell forRowAtIndexPath:(NSIndexPath *)indexPath{
//alternating cell back ground color
if (indexPath.row%2 == 0) {
[cell setBackgroundColor:[UIColor colorWithRed:237.0/255.0f green:237.0/255.0f blue:237.0/255.0f alpha:1.0f]];
}else
{
[cell setBackgroundColor:[UIColor colorWithRed:247.0/255.0f green:247.0/255.0f blue:247.0/255.0f alpha:1.0f]];
}
}
(c)in cellForRowAtIndexPath:
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:#"MyIdentifier"];
if (cell == nil) {
cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:#"MyIdentifier"] autorelease];
cell.selectionStyle = UITableViewCellSelectionStyleNone;
}
//Create your lables/buttons/text/image
nameLabel.test=#"Whatever"; ..... ......
......
if (indexPath.row < [YourArray count]) { Populate your data here in the cells } else { cell.userInteractionEnabled=FALSE; nameLabel.text=#""; } return cell; }
Add dummy cells to the end of your list.

UITable load first UITableViewCell for my last row of UITableViewCell

While coding with UITableView, I encounter this bug that I couldn't understand. I got 3 rows for my table and setting 50px for each row, except the 2nd row that I set it 500px which fill the whole screen. Problem comes when I scroll down to bottom, my bottom role is repeating first row appearance.This is my custom code:
- (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 3;
}
// Customize the appearance of table view cells.
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
static NSString *CellIdentifier = #"TestTable";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil) {
cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier] autorelease];
if (indexPath.section ==0 && indexPath.row==0) {
cell.contentView.backgroundColor = [UIColor redColor];
}
if (indexPath.section ==0 && indexPath.row==1) {
cell.contentView.backgroundColor = [UIColor blueColor];
}
if (indexPath.section ==0 && indexPath.row==2) {
cell.contentView.backgroundColor = [UIColor greenColor];
}
}
// Configure the cell...
return cell;
}
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath {
if (indexPath.row==1) {
return 400;
}
return 50;
}
According to the code, first row is red color, second role is red and third one is blue. But my last row is red color (repeating the first row). If I set my 2nd row to shorter than the screen, e.g. 100px, third row loading fine.
Original Display
After Scroll Down
Appreciate for all kind of advice, as I am running out of ideas how is this happening.
Thanks
When 2nd row is long first row becomes invisible and its cell is reused in last row. That's why you should configure cell each time tableView:cellForRowAtIndexPath: is called i.e. after if (cell == nil) {...} block:
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
static NSString *CellIdentifier = #"TestTable";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil) {
cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier] autorelease];
}
// Configure the cell...
if (indexPath.section == 0 && indexPath.row==0) {
cell.contentView.backgroundColor = [UIColor redColor];
}
if (indexPath.section ==0 && indexPath.row==1) {
cell.contentView.backgroundColor = [UIColor blueColor];
}
if (indexPath.section ==0 && indexPath.row==2) {
cell.contentView.backgroundColor = [UIColor greenColor];
}
return cell;
}