Problem with tableview cell - iphone

I am using these following codes to display multiple images on a table view. One row need to display 4 only images
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
return 1;
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger) section {
//Resize auto complete table based on how many elements will be displayed in the table
return (int)ceil([wordsInSentence count]/4.0);
}
-(void)tableView:(UITableView *)tableView willDisplayCell:(UITableViewCell *)cell forRowAtIndexPath:(NSIndexPath *)indexPath
{
NSLog(#"entered forRowAtIndexPath");
if ((indexPath.row % 2) == 0) {
cell.backgroundColor = [UIColor whiteColor];
}
else {
cell.backgroundColor = [UIColor whiteColor];
}
}
On the button click wich will display table view I wrote the below code
-(IBAction)setImageOnTableView
{
NSLog(#"entered setImageOnTableView");
j=1;
tableView.hidden=NO;
//Breaking the sentence into words and then placing it in an array
wordsInSentence=[[youSaid.text uppercaseString] componentsSeparatedByString:#" "];
[wordsInSentence retain];
[youSaid resignFirstResponder];
[tableView reloadData];
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
UITableViewCell *cell = nil;
NSLog(#"entered cellForRowAtIndexPath");
//j=1;
static NSString *AutoCompleteRowIdentifier = #"AutoCompleteRowIdentifier";
cell = [tableView dequeueReusableCellWithIdentifier:AutoCompleteRowIdentifier];
if (cell == nil) {
cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:AutoCompleteRowIdentifier] autorelease];
[cell.contentView addSubview:nil];
for (int i=0; i <= [wordsInSentence count]; ++i) {
UIImageView *imageView1 = [[[UIImageView alloc] initWithFrame:CGRectMake(30+90*(i%4), 20, 70, 100)] autorelease] ;
imageView1.tag = i+1;
[imageViewArray insertObject:imageView1 atIndex:i];
[cell.contentView addSubview:imageView1];
//[imageView1 release];
}
}
int photosInRow;
if ( (indexPath.row < [tableView numberOfRowsInSection:indexPath.section] - 1) || ([wordsInSentence count] % 4 == 0) ) {
photosInRow = 4;
} else {
photosInRow = [wordsInSentence count] % 4;
}
for ( int i = 1; i <=photosInRow ; i++ ){
imageView = (UIImageView *)[cell.contentView viewWithTag:j];
[self **showImage**:imageView];
}
return cell;
}
//method used to show the images on the table view by checking the category
//and images in the category
-(void)**showImage**:(UIImageView *)imageView
{
NSLog(#"entered showImage");
//this method will check if more than 1 image is present in the category
if([self searchImagesInSameCategory:[wordsInSentence objectAtIndex:j-1]]>1)
{
UIButton *descriptiveButton = [UIButton buttonWithType:UIButtonTypeDetailDisclosure];
[descriptiveButton setFrame:CGRectMake(50, 0, 30, 30)];
[imageView setUserInteractionEnabled:TRUE];
[descriptiveButton addTarget:self action:#selector(showPopOver1:) forControlEvents:UIControlEventTouchUpInside];
descriptiveButton.tag=j;
[imageView addSubview:descriptiveButton];
globalString=[wordsInSentence objectAtIndex:j-1];
}
}
In this code when I displayed 4 images it will display 4. If I displayed 3 images after displaying 4 images, 3 images are displaying but still 4 th image is presenting in table view. How can I fix this. Please can any one help me...
The main problem is, an image view that displayed before is not removing from the cell.

Table cells can be (and in your code, are) cached and reused - which means that for every call to cellForRowAtIndexPath:: you should make sure that the cell you are returning is correct (has the correct images). In your case, I would simply clear the cell of all subviews/image views and recreate them for every fetch.

Related

Expanding UITableViewCell not working as intended

After browsing the internet for various different ways of making expanding/collapsible UITableViewCells, I started my approach earlier today.
I have an array that holds the state of each row in my UITableView(COLLAPSED=0, EXPANDED=1). When the expand button is clicked, I reverse the state in the array, and call reloadSection on whichever section needs to be updates.
In my delegate method heightForRowAtIndexPath, I check to see whether the cell should be expanded or not and return the proper height. The problem I am facing is that my cell does indeed expand, but instead of showing my content hid underneath(I made the cell much bigger with extra info underneath shortened it in IB, and enabled clip subviews to fix the cell overlap), it shows two other grouped UITableViewCells with a similar background as mine and throws the positioning of some labels/buttons off.
I am including pictures of what it looks like normally and expanded. I have gone through the code and it all looks okay, I think there may be a setting I need to change in order for this to render properly.
Here is the source:
#define UITABLEVIEWCELLSIZE_COLLAPSED 97
#define UITABLEVIEWCELLSIZE_EXPANDED 285
#define EXPANDED 1
#define COLLAPSED 0
-(CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
{
NSNumber *state = [cellExpansionArray objectAtIndex:[indexPath section]];
if ([state intValue] == COLLAPSED) {
return UITABLEVIEWCELLSIZE_COLLAPSED;
}else if([state intValue] == EXPANDED) {
return UITABLEVIEWCELLSIZE_EXPANDED;
}
return UITABLEVIEWCELLSIZE_COLLAPSED;
}
//expandCell is called when the arrow indicator is clicked on the cell
-(IBAction)expandCell:(id)sender
{
NSInteger cellNumber = [sender tag];
NSNumber *state = [cellExpansionArray objectAtIndex:cellNumber];
if (state.intValue == 0) {
[cellExpansionArray replaceObjectAtIndex:cellNumber withObject:[NSNumber numberWithInt:EXPANDED]];
}else if (state.intValue == 1) {
[cellExpansionArray replaceObjectAtIndex:cellNumber withObject:[NSNumber numberWithInt:COLLAPSED]];
}
//[self.tableView beginUpdates];
//[self.tableView endUpdates];
//[self.tableView reloadSections:[[NSIndexSet alloc] initWithIndex:cellNumber] withRowAnimation:UITableViewRowAnimationAutomatic];
[self.tableView reloadData];
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *CellIdentifier = #"PCFCustomCell";
PCFCustomTableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
//cell.autoresizingMask = UIViewAutoresizingFlexibleHeight;
[cell setBackgroundColor:[UIColor colorWithPatternImage:[UIImage imageNamed:#"1slot.png"]]];
PCFClassModel *course = [classesOffered objectAtIndex:[indexPath section]];
cell.courseCRN.text = [course CRN];
cell.courseDataRange.text = [course dateRange];
cell.courseDaysOffered.text = [course days];
cell.courseHours.text = [course credits];
cell.courseInstructor.text = [course instructor];
cell.courseTime.text = [course time];
cell.courseLocation.text = [course classLocation];
cell.courseSection.text = [course sectionNum];
cell.courseName.text = [course courseNumber];
cell.courseTitle.text = [course classTitle];
cell.courseType.text = [course scheduleType];
//cell.professorEmail.text = [course instructorEmail];
[cell.mailProf setTag:[indexPath section]];
[cell.showCatalog setTag:[indexPath section]];
[cell.followClass setTag:[indexPath section]];
[cell.addToSchedule setTag:[indexPath section]];
[cell.buttonDropDown setTag:[indexPath section]];
[cell.mailProf setHidden:NO];
[cell.mailProf setEnabled:YES];
if (![course instructorEmail]) {
[cell.mailProf setTitle:#"NO EMAIL PROVIDED" forState:UIControlStateNormal];
[cell.mailProf setEnabled:NO];
}
[cell.followClass setBackgroundImage:[UIImage imageNamed:#"search_res_11.png"] forState:UIControlStateNormal];
[cell.addToSchedule setBackgroundImage:[UIImage imageNamed:#"search_res_09.png"] forState:UIControlStateNormal];
if ([savedResults count] > 0) {
for (PCFClassModel *courseTwo in savedResults) {
if ([[courseTwo CRN] isEqualToString:[course CRN]]) {
[[cell followClass] setBackgroundImage:[UIImage imageNamed:#"favorite_activated.png"] forState:UIControlStateNormal];
break;
}
}
}
//schedule
if ([savedSchedule count] > 0) {
for (PCFClassModel *courseTwo in savedSchedule) {
if ([[courseTwo CRN] isEqualToString:[course CRN]]) {
[[cell addToSchedule] setBackgroundImage:[UIImage imageNamed:#"purdue_activated.png"] forState:UIControlStateNormal];
break;
}
}
}
[cell.mailProf addTarget:self action:#selector(mailProf:) forControlEvents:UIControlEventTouchUpInside];
[cell.showCatalog addTarget:self action:#selector(showCatalog:) forControlEvents:UIControlEventTouchUpInside];
[cell.followClass addTarget:self action:#selector(followClass:) forControlEvents:UIControlEventTouchUpInside];
[cell.addToSchedule addTarget:self action:#selector(addToSchedule:) forControlEvents:UIControlEventTouchUpInside];
[cell.buttonDropDown addTarget:self action:#selector(expandCell:) forControlEvents:UIControlEventTouchUpInside];
//get internet data
/*
[[cell staticAvailable] setHidden:YES];
[[cell available] setHidden:YES];
[cell.available setText:#""];
[[cell remainingActivityIndicator] startAnimating];
dispatch_queue_t getSpots = dispatch_queue_create("GetSpots", nil);
dispatch_async(getSpots, ^{
NSString *webData = nil;
while (!webData && self.view.window) webData = [PCFWebModel queryServer:[course classLink] connectionType:nil referer:#"https://selfservice.mypurdue.purdue.edu/prod/bwckschd.p_get_crse_unsec" arguements:nil];
if (!self.view.window) return;
NSArray *courseRecord = [PCFWebModel parseData:webData type:3];
PCFCourseRecord *record = [courseRecord objectAtIndex:0];
dispatch_async(dispatch_get_main_queue(), ^{
[[cell remainingActivityIndicator] stopAnimating];
[[cell staticAvailable] setHidden:NO];
NSString *val = #"1";
if ([val compare:record.enrolled] > 0) {
//[[cell available] setTextColor:[UIColor redColor]];
}else {
//[[cell available] setTextColor:[UIColor colorWithRed:.0565442 green:.430819 blue:.0724145 alpha:1]];
}
[[cell available] setText:[NSString stringWithFormat:#"SLOTS: %#/%#", record.enrolled,record.capacity]];
[[cell available] setHidden:NO];
[PCFAnimationModel fadeTextIntoView:cell.available time:1];
[PCFAnimationModel fadeTextIntoView:cell.staticAvailable time:1];
});
});
*/
// Configure the cell...
//[PCFFontFactory convertViewToFont:cell];
[cell.courseTitle setFont:[PCFFontFactory droidSansFontWithSize:13]];
[cell.courseName setFont:[PCFFontFactory droidSansFontWithSize:38]];
[cell.courseDaysOffered setFont:[PCFFontFactory droidSansBoldFontWithSize:11]];
NSNumber *state = [cellExpansionArray objectAtIndex:indexPath.section];
if (state.intValue == COLLAPSED) {
[cell.imageViewBackground setHidden:YES];
}else {
//[cell.imageViewBackground setHidden:NO];
}
return cell;
}
This looks like an autosizing issue to me! Subviews of your cell have flexible margins & width,height. I can give few suggestions and not the exact solution. Hope they help..
Try removing the autosizing properties to subviews (In XIB click on view->goto Size inspector->Autosizing) OR
Create 2 different cell templates to be used during states expand and collapse. Same Cell XIB with 2 different cell views. Use UINib to load the xib.
Dont use pattern image as cell background if image is fixed size. Make use of stretchableImageWithLeftCapWidth:topCapHeight image API.
Cheers!
Amar.
Not sure if this will help your situation. But often if you want to animate reloading cells in a table after changing the height without doing reloads and suchlike, you can just do the following.
[tableview beginUpdates];
[tableview endUpdates];
You haven't posted your cellForRowAtIndexPath but I am guessing you are wrongly reusing cells there. Check the answer to a similar question:
Objective C UITableView - Table cells display wrong content after changing cell's height
I tried with a code similar to yours and it seems to work as expected.
- (void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
states = [[NSMutableArray alloc] init];
for (int i = 0; i < 10; i++)
{
[states addObject:[NSNumber numberWithBool:false]];
}
}
- (void)didReceiveMemoryWarning
{
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
{
return 10;
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
return 1;
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:#"cellId"];
cell.textLabel.text = [NSString stringWithFormat:#"Title #%d", indexPath.section];
cell.detailTextLabel.text = [NSString stringWithFormat:#"Subtitle #%d", indexPath.row];
return cell;
}
- (void)tableView:(UITableView *)tableView accessoryButtonTappedForRowWithIndexPath:(NSIndexPath *)indexPath
{
NSNumber *state = [states objectAtIndex:indexPath.section];
[states replaceObjectAtIndex:indexPath.section withObject:[NSNumber numberWithBool:!state.boolValue]];
[self.tableView reloadData];
}
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
{
NSNumber *state = [states objectAtIndex:indexPath.section];
if (state.boolValue == false)
{
return 100;
}
else
{
return 244;
}
}

Adding UIActivityIndicator to UITableView

I need to load some data in a table view and while this is going on in the background I want to add an activity indicator in order to show that there is a process going on and will hide once the process finishes. What would be the most efficient way to implement something like this?
Depends, whether you want to block your user or not and also how important is the activity indication.
If you don't want to block user, use Application.networkActivityIndicatorVisible, if you want to have larger activity indicator and still not to block user, animate UIView with text and UIActivityIndicator below the table view (tableview.height -= activityview.height) and then hide on complete or if you would like to block user, use blocking activity indicator.
http://www.dejal.com/developer/?q=developer/dsactivityview
https://github.com/jdg/MBProgressHUD (I was using MBProgressHUD personally and it's easy to learn and use)
You can add a view which has a UIIndicatorView and a UILabel as your cell's subview. You can use this way to show error data loading/ error network/ empty data...
Example:
Your Controller can define two modes: UITableViewModeMessage and UITableViewModeData.
In viewDidLoad, you set self.tableViewMode = UITableViewModeMessage. When has returned data, set self.tableViewMode = UITableViewModeData and reload data for tableview.
Some code:
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
if (self.tableViewMode == UITableViewModeMessage) {
return 2;
} else {
return self.yourEntries ? self.yourEntries.count : 0;
}
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
if (self.tableViewMode == UITableViewModeMessage) {
return [self tableView:tableView messageCellForRowAtIndexPath:indexPath];
} else {
return [self tableView:tableView dataCellForRowAtIndexPath:indexPath];
}
}
- (void)tableView:(UITableView *)tableView willDisplayCell:(UITableViewCell *)cell forRowAtIndexPath:(NSIndexPath *)indexPath
{
// Remove Loading... progress view if exist.
UIView *progressView = [cell viewWithTag:100];
[progressView removeFromSuperview];
if (self.tableViewMode == UITableViewModeMessage) {
if (indexPath.row == 1) {
// remove the current label.
cell.textLabel.text = nil;
// We build progress view and attach to cell here but not in cellForRowAtIndexPath is because in this method cell frame is already calculated.
UIView *progressView = [self progressViewForCell:cell message:#"Loading..." alpha:0.9];
[cell addSubview:progressView];
}
}
}
// cell to display when loading
- (UITableViewCell *)tableView:(UITableView *)tableView messageCellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *CellIdentifier = #"MessageCell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil) {
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier];
cell.textLabel.textColor = [UIColor grayColor];
cell.textLabel.textAlignment = UITextAlignmentCenter;
}
if (indexPath.row == 1) {
cell.textLabel.text = #"Loading...";
} else {
cell.textLabel.text = nil;
}
return cell;
}
// cell to display when has data
- (UITableViewCell *)tableView:(UITableView *)tableView dataCellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *CellIdentifier = #"DataCell";
if (cell == nil) {
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier];
}
cell.textLabel.text = [[self.yourEntries objectAtIndex:indexPath.row] description];
return cell;
}
// Build a view which has a UIActivityIndicatorView and a UILabel
- (UIView *)progressViewForCell:(UITableViewCell *)cell message:(NSString *)message alpha:(CGFloat)alpha
{
// NOTE: progressView needs to be removed from cell in cellForRowAtIndexPath:
CGRect progressViewFrame = CGRectZero;
progressViewFrame.size.width = CGRectGetMaxX(cell.bounds);
progressViewFrame.size.height = CGRectGetMaxY(cell.bounds) - 2;
UIView *progressView = [[UIView alloc] initWithFrame:progressViewFrame];
progressView.backgroundColor = RGBA(255, 255, 255, 1);
progressView.alpha = alpha;
progressView.tag = 100;
UILabel *loadingLabel = [[UILabel alloc] initWithFrame:progressView.bounds];
loadingLabel.backgroundColor = [UIColor clearColor];
loadingLabel.font = [UIFont systemFontOfSize:14];
loadingLabel.textColor = [UIColor blackColor];
loadingLabel.textAlignment = UITextAlignmentCenter;
loadingLabel.text = message;
CGFloat widthOfText = [loadingLabel.text sizeWithFont:loadingLabel.font].width;
CGFloat spaceBetweenIndicatorAndLabel = 5;
// activityIndicatorView has size in which width and height is equal to 20.
UIActivityIndicatorView *activityIndicatorView = [[UIActivityIndicatorView alloc] initWithActivityIndicatorStyle:UIActivityIndicatorViewStyleGray];
[activityIndicatorView setCenter:CGPointMake(CGRectGetMidX(cell.bounds) - (widthOfText / 2) - (activityIndicatorView.bounds.size.width / 2) - spaceBetweenIndicatorAndLabel, CGRectGetMidY(cell.bounds))];
[activityIndicatorView setColor:[UIColor blackColor]];
[activityIndicatorView startAnimating];
[progressView addSubview:activityIndicatorView];
[progressView addSubview:loadingLabel];
return progressView;
}

UITableViewCell disorder when reloading rows to expand and shrink

I'm facing a crazy issue which is about expanding and shrinking UITableViewCell. When I click just one cell it works properly but while one cell remains open, clicking another cell to open causes the cell disorder. I would want to expand and shrink at the same time.
Here is my source.
- (void)viewDidLoad {
[super viewDidLoad];
//Initialize the array.
listOfItems = [[NSMutableArray alloc] init];
//Add items
[listOfItems addObject:#"1"];
[listOfItems addObject:#"2"];
[listOfItems addObject:#"3"];
[listOfItems addObject:#"4"];
[listOfItems addObject:#"5"];
[listOfItems addObject:#"6"];
[listOfItems addObject:#"7"];
[listOfItems addObject:#"8"];
}
- (void)didReceiveMemoryWarning {
[super didReceiveMemoryWarning]; // Releases the view if it doesn't have a superview
// Release anything that's not essential, such as cached data
}
#pragma mark Table view methods
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
return 1;
}
// Customize the number of rows in the table view.
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
return [listOfItems count];
}
// Customize the appearance of table view cells.
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
UILabel *aLabel; UILabel *bLabel; UILabel *v1Label; UILabel *v2Label;; UIView *v1; UIView *v2;
static NSString *CellIdentifier = #"Cell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil) {
NSLog(#" cell null");
cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier] autorelease];
aLabel = [[[UILabel alloc] initWithFrame:CGRectMake(9.0, 8.0, 50.0, 20.0)] autorelease];
aLabel.tag = 1;
aLabel.font = [UIFont systemFontOfSize:30];
[cell.contentView addSubview:aLabel];
v1 = [[UIView alloc] initWithFrame:CGRectMake(0, 44, 320, 116)];
v1.backgroundColor = [UIColor redColor];
v1.tag = 10;
v1.hidden = YES;
[cell.contentView addSubview:v1];
[v1 release];
v2 = [[UIView alloc] initWithFrame:CGRectMake(0, 44, 320, 100)];
v2.backgroundColor = [UIColor blueColor];
v2.tag = 11;
v2.hidden = YES;
[cell.contentView addSubview:v2];
[v2 release];
}
else {
aLabel = (UILabel *)[cell.contentView viewWithTag:1];
v1 = (UIView *) [cell.contentView viewWithTag:10];
v2 = (UIView *) [cell.contentView viewWithTag:11];
}
aLabel.text = [listOfItems objectAtIndex:indexPath.row];
if (SelectedIndexPath == indexPath.row)
{
if ([aLabel.text intValue] % 2) {
v1.hidden = NO;
v2.hidden = YES;
}
else {
v1.hidden = YES;
v2.hidden = NO;
}
}
else {
v1.hidden = YES;
v2.hidden = YES;
}
return cell;
}
-(CGFloat) tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
{
if (SelectedIndexPath == indexPath.row)
{
return 100.0;
}
else {
return 46.0;
}
}
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
if (SelectedIndexPath == -1)
{
OldSelectedIndexPath = indexPath.row;
SelectedIndexPath = indexPath.row;
[tableView reloadRowsAtIndexPaths:[NSArray arrayWithObjects:indexPath, nil] withRowAnimation:NO];
}
else
{
if (SelectedIndexPath == indexPath.row)
{
OldSelectedIndexPath = SelectedIndexPath;
SelectedIndexPath = -1;
[tableView reloadRowsAtIndexPaths:[NSArray arrayWithObjects:indexPath, nil] withRowAnimation:NO];
}
else
{
SelectedIndexPath = indexPath.row;
[tableView reloadRowsAtIndexPaths:[NSArray arrayWithObjects:[NSIndexPath indexPathForRow:OldSelectedIndexPath inSection:indexPath.section], indexPath, nil] withRowAnimation:NO];
OldSelectedIndexPath = SelectedIndexPath;
}
}
}
The problem comes from the facth that your cell will have a height of 160.0 when selected.
Look here
v1 = [[UIView alloc] initWithFrame:CGRectMake(0, 44, 320, 116)];
You give an heigh of 116 to a view which y origin is 44. Thus your cell view will have a total height of 160.0
Change the value returned in
-(CGFloat) tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
To match the correct total height of your cell.
The problem is in
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
Or may be the problem is due to releasing. anything is going to release and you are still using it.
first comment // all release and inter prate your
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath

Align cells to bottom and top of UITableView, leaving stretchable gap in middle

I have a table view with five cells displaying the settings of my app. I want the first four cells to appear at the top. The last cell isn't actually a setting, it says "Legal" and takes you to the EULA, so I want it to appear at the bottom.
Now I know I could use – tableView:viewForHeaderInSection: and– tableView:heightForHeaderInSection: to create some padding, but I really don't like hardcoding in dimensions this way. I also don't want to use UIButton, because I want it to be exactly the same style as the rest of the cells.
Does anyone know the best practice for going about this?
I'm assuming you're using a grouped table view, like the settings app. What I've done is created a group section between the top and bottom group sections, to which I've add a 'transparent' row cell, that I size dynamically.
I've created a simple demo for you using hardcoded values, but hopefully you'll get the idea. Obviously you would get the number of sections and the number of rows from your data structure:
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
return 3;
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
int rtn = 0;
if (section == 0)
rtn = 4;
else if (section == 1)
rtn = 1;
else if (section == 2)
rtn = 1;
return rtn;
}
/*
- (CGFloat)tableView:(UITableView *)tableView heightForHeaderInSection:(NSInteger)section {
return 44.0f;
}
*/
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath {
int TOTALCELLS = 6;
float CONSTANT = 0.5f;
if (indexPath.section == 1)
return self.view.frame.size.height - (44.0f * (CONSTANT + TOTALCELLS));
return 44.0f;
}
- (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];
}
if (indexPath.section == 0)
{
if (indexPath.row == 0) {
cell.textLabel.text = #"My Switch";
UISwitch *boolSwitch = [[UISwitch alloc]initWithFrame:CGRectZero];
boolSwitch.on = YES;
[cell setAccessoryView:boolSwitch];
[boolSwitch release];
} else if (indexPath.row == 1) {
cell.textLabel.text = #"My TxtField";
[cell setSelectionStyle:UITableViewCellSelectionStyleNone];
UITextField *txtField = [[UITextField alloc]initWithFrame:CGRectMake(0,0,175,20)];
txtField.text = #"Default Value";
txtField.textColor = [UIColor darkGrayColor];
[txtField setClearButtonMode:UITextFieldViewModeAlways];
[cell setAccessoryView:txtField];
[txtField release];
} else if (indexPath.row == 2) {
cell.selectionStyle=UITableViewCellSelectionStyleNone;
UISlider *slider = [[UISlider alloc] initWithFrame:CGRectMake(0,0,280,22)];
slider.minimumValue = 0.0f;
slider.maximumValue = 10.0f;
slider.value = 0.7f;
slider.minimumValueImage = [UIImage imageNamed:#"minus.png"];
slider.maximumValueImage = [UIImage imageNamed:#"plus.png"];
[cell setAccessoryView:slider];
[slider addTarget:self action:#selector(sliderChange:forEvent:) forControlEvents:UIControlEventValueChanged];
[slider release];
} else if (indexPath.row == 3) {
cell.textLabel.text = #"My MultiValue";
cell.accessoryType = UITableViewCellAccessoryDisclosureIndicator;
cell.detailTextLabel.text = #"Default selection";
}
} else if (indexPath.section == 1) {
UIView *transCell = [[UIView alloc] initWithFrame:CGRectZero];
transCell.backgroundColor = [UIColor clearColor];
cell.backgroundView = transCell;
[transCell release];
[cell setSelectionStyle:UITableViewCellSelectionStyleNone];
} else if (indexPath.section == 2) {
cell.textLabel.text = #"Legal";
cell.accessoryType = UITableViewCellAccessoryDisclosureIndicator;
}
return cell;
}
The critical parts are in cellForRowAtIndexPath, where the transparent row is created. The trick here is to add the transparent view to the cell's backgroundView, and set the cell selection style to None.
UIView *transCell = [[UIView alloc] initWithFrame:CGRectZero];
transCell.backgroundColor = [UIColor clearColor];
cell.backgroundView = transCell;
[transCell release];
[cell setSelectionStyle:UITableViewCellSelectionStyleNone];
and in heightForRowAtIndexPath, the dynamic sizing of the transparent row.
self.view.frame.size.height - (44.0f * (CONSTANT + TOTALCELLS));
TOTALCELLS is the total of all of the cells, including the transparent one. You may need to do additional work on this algorithm, as it doesn't take into consideration what happens when number of cells grows beyond what is visible, and I haven't tested it with various combinations of navigation and toolbars.
I hope this works for you.

UITableView's background color becoming white when section is empty

Here is the deal: I have a UITableView with 2 sections, and I want to display a "no data" cell when the first section is empty, so that the 2 section headers are not stuck together (cause it looks weird).
It works great (even though I had trouble making it work at first, see this thread). I'm using viewForFooterInSection :
- (CGFloat)tableView:(UITableView *)tableView heightForFooterInSection:(NSInteger)section {
if(section == 0)
{
if([firstSectionArray count] == 0)
return 40;
else
return 0;
}
return 0;
}
- (UIView *)tableView:(UITableView *)tableView viewForFooterInSection:(NSInteger)section{
if(section == 0)
{
UILabel *label = [[UILabel alloc] initWithFrame:CGRectMake(200, 10, 50, 44)];
label.backgroundColor = [UIColor clearColor];
label.textColor = [UIColor colorWithWhite:0.6 alpha:1.0];
label.textAlignment = UITextAlignmentCenter;
label.lineBreakMode = UILineBreakModeWordWrap;
label.numberOfLines = 0;
label.text = #"No row";
return [label autorelease];
}
return nil;
}
But the background color turns plain white when I display the section footer view. See image:
alt text http://img683.yfrog.com/img683/9480/uitableviewproblem.png
I like it better when the background is filled with empty cells. Does anyone have any idea how to do that? Thanks
The background is filled with empty cells when you have no footer. So do not implement a viewForFooterInSection (or titleForFooterInSection) method, and you will get the "empty cells" effect.
I'd recommend that you return a cell indicating that there are no entries to show, like so:
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
if (matches.count>0) {
// Do your usual thing here
} else {
static NSString *cellId = #"noDataCell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:cellId];
if (cell == nil) {
cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:cellId] autorelease];
cell.textLabel.textAlignment = UITextAlignmentCenter;
cell.textLabel.textColor = [UIColor grayColor];
}
cell.textLabel.text = #"Aucun match";
return cell;
}
}
And of course, you would have to tell UIKit that you always have at least one cell in your section... I've added the isDeletingRow case that seems to trouble you (in comment).
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
if (section==0) return matches.count>0 ? matches.count : (isDeletingRow ? 0 : 1);
// Set 'isDeletingRow' to YES when a delete is being committed to the table, in that case we let UIKit know that we indeed took care of the delete...
// And cover the other sections too...
}
When you are committing the edits, you need to set isDeletingRow for numberOfRowsInSection to return a satisfactory value...
- (void)tableView:(UITableView *)tableView commitEditingStyle:(UITableViewCellEditingStyle)editingStyle forRowAtIndexPath:(NSIndexPath *)indexPath {
if (editingStyle == UITableViewCellEditingStyleDelete) {
isDeletingRow = YES;
// Your current code when a row is deleted here...
isDeletingRow = NO;
if (matches.count==0) [self.tableView performSelector:#selector(reloadData) withObject:nil afterDelay:0.5];
}
}