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;
Related
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);
}
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:#"-"].
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
{
}
I want to make a typical situation: when user selects any cell, it's accessoryType turns in checkmark. Only one cell's accessoryType can be checkmark. And then I wanna save in NSUserDefaults indexPath.row so my app will be able to know which cell user selected and make some changes in options. So I wrote this wrong code:
didSelectRowAtIndexPath
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
// checkedIndexPath is NSIndexPath
if(self.checkedIndexPath)
{
UITableViewCell* uncheckCell = [tableView
cellForRowAtIndexPath:self.checkedIndexPath];
uncheckCell.accessoryType = UITableViewCellAccessoryNone;
}
UITableViewCell* cell = [tableView cellForRowAtIndexPath:indexPath];
cell.accessoryType = UITableViewCellAccessoryCheckmark;
self.checkedIndexPath = indexPath;
[[NSUserDefaults standardUserDefaults]setObject:[NSNumber numberWithInt:self.checkedIndexPath.row]forKey:#"indexpathrow" ];
}
cellForRowAtIndexPath
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
// Part of code from cellForRowAtIndexPath
if(indexPath.row == [[[NSUserDefaults standardUserDefaults]objectForKey:#"indexpathrow"]intValue ])
{
cell.accessoryType = UITableViewCellAccessoryCheckmark;
}
else
{
cell.accessoryType = UITableViewCellAccessoryNone;
}
return cell;
}
However, this code works badly. When you open the UITableView, there is an already selected cell in the table and when you press another there are two checkmarked cells...How can I improve my code or should I change it whole ? Any suggestions ?
Thanks !
Try this code:
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
// checkedIndexPath is NSIndexPath
NSIndexPath *previousSelection = self.checkedIndexPath;
NSArray *array = nil;
if (nil != previousSelection) {
array = [NSArray arrayWithObjects:previousSelection, indexPath, nil];
} else {
array = [NSArray arrayWithObject:indexPath];
}
self.checkedIndexPath = indexPath;
[tableView reloadRowsAtIndexPaths:array withRowAnimation: UITableViewRowAnimationNone];
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
// Part of code from cellForRowAtIndexPath
NSString *cellID = #"CellID";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:cellID];
if (nil == cell) {
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:cellID];
[cell autorelease];
}
// some code for initializing cell content
cell.selectionStyle = UITableViewCellSelectionStyleNone;
if(self.checkedIndexPath != nil && indexPath.row == self.checkedIndexPath.row)
{
cell.accessoryType = UITableViewCellAccessoryCheckmark;
} else {
cell.accessoryType = UITableViewCellAccessoryNone;
}
return cell;
}
This
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
UITableViewCell *cell = [tableView cellForRowAtIndexPath:indexPath];
if (cell.accessoryType == UITableViewCellAccessoryNone) {
cell.accessoryType = UITableViewCellAccessoryCheckmark;
}
else {
cell.accessoryType = UITableViewCellAccessoryNone;
}
[tableView deselectRowAtIndexPath:indexPath animated:YES];
}
... modifies the "accessoryType" of every 6th cell INSTEAD of just the selected row. What am I missing?
Thanks
UPDATED: Here is the cell creation code ...
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
static NSString *TC = #"TC";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier: TC];
if (cell == nil) {
cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:PlayerTableViewCell] autorelease];
}
NSUInteger row = [indexPath row];
cell.textLabel.text = [NSString stringWithFormat:#"Person %d", row+1];
return cell;
}
MY SOLUTION based on the marked answer below is ...
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
// EVERY row gets its one Identifier
NSString *TC = [NSString stringWithFormat: #"TC%d", indexPath.row];
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier: TC];
if (cell == nil) {
cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:TC] autorelease];
}
NSUInteger row = [indexPath row];
cell.textLabel.text = [NSString stringWithFormat:#"Person %d", row+1];
return cell;
}
If there is a better way I'm all ears. Would be nice if we could just change the SPECIFIC Cell according to the NSIndexPath passed in someday (at least that seems a whole lot more intuitive to me).
I got it to work by using setting the accessory type in cellForRowAtIndexPath based on variable which keeps track of the selected row. Then in didSelectRowAtIndexPath i just deselect the row, update the variable, and reload the table.
CODE SAMPLE:
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
static NSString *CellIdentifier = #"Cell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil) {
cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleValue1 reuseIdentifier:CellIdentifier] autorelease];
}
cell.textLabel.text = [NSString stringWithFormat:#"%d", indexPath.row];
if ([_cells indexOfObjectIdenticalTo:_selectedCell] == indexPath.row) {
cell.accessoryType = UITableViewCellAccessoryCheckmark;
} else {
cell.accessoryType = UITableViewCellAccessoryNone;
}
return cell;
}
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
[tableView deselectRowAtIndexPath:indexPath animated:NO];
_selectedCell = [_cells objectAtIndex:indexPath.row];
[tableView reloadData];
}
Yeah, just figured out. These are the same cells ( logs below are NSLog( #"%d %#", row, cell ) ).
2010-04-15 12:43:40.722 ...[37343:207] 0 <MyListCell: 0x124bee0; baseClass = UITableViewCell; frame = (0 0; 320 44); autoresize = RM+TM; layer = <CALayer: 0x124c3a0>>
2010-04-15 12:43:47.827 ...[37343:207] 10 <MyListCell: 0x124bee0; baseClass = UITableViewCell; frame = (0 31; 340 44); autoresize = W; layer = <CALayer: 0x124c3a0>>
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier: PlayerTableViewCell];
dequeueReusableCellWithIdentifier uses already created cell, if the previous one is out of a screen.
So, you should avoid using "dequeueReusableCellWithIdentifier" - create a dictionary NSIndexPath -> UITableViewCell and use it instead of dequeueReusableCellWithIdentifier.
ADDED:
You can also check if the (rowNumber+1) exists in a winningNumbers array and replace accessory in a tableView:cellForRowAtIndexPath: method. This should work too