How to use 3 different cells on one uitableview? I have 3 buttons now When i press any button then cell of table view should be changed. Please help
In the button's action method, save which button was tapped & reload the row in which you want to change the cell.
-(void)button1Tapped:(id)sender
{
self.buttonIndex = 1;
NSArray* arr = [[NSArray alloc] initWithObjects:self.indexPathOfConcernedCell, nil];
[self.tableView reloadRowsAtIndexPaths:arr withRowAnimation:UITableViewRowAnimationNone];
[arr release];
}
Then, in cellForRowAtIndexPath: return the cell one the basis of which button was pressed-
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
if(indexPath == self.indexPathOfConcernedCell)
{
if(self.buttonIndex == 1)
{
Cell1* cell = (Cell1*) [tableView dequeueReusableCellWithIdentifier:#"CellIdentifier1"];
if(cell == nil)
{
cell = [[[Cell1 alloc] initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:#"CellIdentifier1"] autorelease];
}
}
else if(self.buttonIndex == 2)
{
//do similar stuff
}
//do similar stuff for buttonIndex 3 here
}
}
else
{
//your regular stuff
}
return cell;
}
Related
I am creating a table with three different types of custom cell, One of them, one custom cell is having UITextField. I create two rows using this custom cell. I set tag and delegate for textfields of both row.
My problem is, when I scroll the table, these rows with textfields move up and disappear from the screen, when scroll down, that time my app gets crash.
I get an error like
-[CellImageViewController txtField]: unrecognized selector sent to instance 0xa0ea5e0
Here is my code for cellForRowAtIndexPath:
if (indexPath.row == 0 )
{
if (cell == nil) {
cell = [[[CellWithTextFieldViewController alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:cellID] autorelease];
}
cell.txtField.tag =1;
cell.txtField.delegate = self;
cell.txtField.text = #"kjfkd";
}
return cell;
}
else if(indexPath.row==1)
{
if (cell == nil) {
cell = [[[CellWithTextFieldViewController alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:cellID] autorelease];
}
cell.txtField.tag = 2;
cell.txtField.text = #"glk";
cell.txtField.delegate = self;
return cell;
}
Any one have idea about this issue?
you have different type of cells, so you need to use a cellIdentifier different for each one.
Try this:
customOrNormalCell *cell [tableView dequeueReusableCellWithIdentifier:CellIdentifier]
if(!cell){
cell = [[CellWithTextFieldViewController alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:[NSString stringWithFormat:#"%i", indexPath.row]];
}
With this code, each cellIdentifier will be 1,2,3,4... (All different)
I'm pretty sure that it will solves the problem
create UITextField before create UITableView and Add your Textfield object in cell Content view
[cell.contentView addSubview:yourTxtFieldOblect];
It looks like you might be reusing a cell of a different type.
Try making sure which kind of class the cell you are reusing is before trying to access it's properties.
why you are define cell for each row?
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
NSString *CellIdentifier = [NSString stringWithFormat:#"Cell%d",indexPath.row];
CellWithTextFieldViewController *cell = (CellWithTextFieldViewController *)[tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if(cell == nil)
{
cell =[[[CellWithTextFieldViewController alloc] initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:CellIdentifier]autorelease];
cell.txtField.tag = indexPath.row;
cell.txtField.text = [SET TEXT FROM ARRAY];
cell.txtField.delegate = self;
}
}
I had also faced this problem in my project.
just try this:
Disabled the scrolling property in Tableview and create a scrollview.Then add your Tableview in your scrollview.
UITableView *table=[[UITableView alloc]initWithFrame:CGRectMake(0, 0, 976, 395) style:UITableViewStylePlain];
[table setSeparatorStyle:UITableViewCellSelectionStyleNone];
UIScroll *scroll=[[UIScrollView alloc]initWithFrame:CGRectMake(24, 168, 978, 395)];
[table setScrollEnabled:NO];
[scroll addSubview:table];
[self.view addSubview:scroll];
[scroll sendSubviewToBack:table];
Try this
static NSString *cellIdentifier= #"Cell";
CellWithTextFieldViewController *cell = (CellWithTextFieldViewController *)[tableView dequeueReusableCellWithIdentifier:cellIdentifier];
if (cell == nil) {
cell = [[CellWithTextFieldViewController alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:cellIdentifier];
}
cell.txtField.tag =indexPath.row+1;
cell.txtField.delegate = self;
cell.txtField.text = #"kjfkd";
return cell;
While scrolling tableView your cell is getting reused. Thats why textField is disappearing. Try to use different cell id for different custom cells. Dont forget to give the same id in nib file for cell identifier
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *customCellOne = #"customCell1";
static NSString *customCellTwo = #"customCell2";
UITableViewCell *cell =nil;
if (0 == indexPath.row)
{
cell = (CustomCellOne *)[tableView dequeueReusableCellWithIdentifier:customCellOne];
if (nil == cell)
{
// Create custom cell one and do what ever you want
}
}
else if (1 == indexPath.row)
{
cell=(CustomCellTwo *)[tableView dequeueReusableCellWithIdentifier:customCellTwo];
if (nil == cell)
{
// Create custom cell two and do what ever you want
}
}
return cell;
}
I don't know,may be when reused the cell,the textfield delegate was released.
may be you can set the
textfield.deleagate = self;
in CellWithTextFieldViewController.m
I have a table view that needs a custom UITableViewCellAccessoryCheckmark. The checkmark displays when a row is selected and disappears when anther row is selected and then appears on the last most selected view. That works fine.
the problem arises when I use this line:
cell.accessoryView = [[ UIImageView alloc ]
initWithImage:[UIImage imageNamed:#"icon-tick.png" ]];
to add a custom UITableViewCellAccessoryCheckmark. After that code the UITableViewCellAccessoryCheckmark remain on all rows and don't disappear when another row is touched.
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
int index = indexPath.row; id obj = [listOfItems objectAtIndex:index];
UITableViewCell *cell = [self.tableView cellForRowAtIndexPath:indexPath];
NSLog(#"%d",indexPath.row);
if (rowNO!=indexPath.row) {
rowNO=indexPath.row;
[self.tableView cellForRowAtIndexPath:indexPath].accessoryType=UITableViewCellAccessoryCheckmark;
cell.accessoryView = [[ UIImageView alloc ]
initWithImage:[UIImage imageNamed:#"icon-tick.png" ]];
[self.tableView cellForRowAtIndexPath:lastIndexPth].accessoryType=UITableViewCellAccessoryNone;
lastIndexPth=indexPath;
}
A much cleaner and cooler way would be to overwrite UITableViewCell like this:
- (void)setAccessoryType:(UITableViewCellAccessoryType)accessoryType
{
// Check for the checkmark
if (accessoryType == UITableViewCellAccessoryCheckmark)
{
// Add the image
self.accessoryView = [[[UIImageView alloc] initWithImage:[UIImage imageNamed:#"YourImage.png"]] autorelease];
}
// We don't have to modify the accessory
else
{
[super setAccessoryType:accessoryType];
}
}
If you have done that, you can continue using UITableViewCellAccessoryCheckmark because your class will automatically replace it with an image.
You should only set the style in your cellForRowAtIndexPath method. Like this:
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
// [init subclassed cell here, dont forget to use the table view cache...]
cell.accessoryType = (rowNO != indexPath.row ? nil : UITableViewCellAccessoryCheckmark);
return cell;
}
And then, you just have to update rowNO in didSelectRowAtIndexPath to update your data and redraw the cell, like this:
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
if (rowNO != indexPath.row)
{
rowNO = indexPath.row;
}
[self.tableView reloadData];
}
Also, instead of reloading the whole table with [self.tableView reloadData], you could only reload the two cells that change their style (e.g. checkmark) using reloadRowsAtIndexPaths.
Hm don't know why but i can't add comments so im writing this as answer. The problem with Blauesocke answer is that the AccessoryType wil be not set to UITableViewCellAccessoryCheckmark so you can't check the cell AccessoryType. Is there some way to do it right so the cell AccessoryType will be corect type just another image.
I'm using the method like this :
- (void)setAccessoryType:(UITableViewCellAccessoryType)newAccessoryType
{
[super setAccessoryType:newAccessoryType];
// Check for the checkmark
switch(newAccessoryType)
{
case UITableViewCellAccessoryCheckmark:
self.accessoryView = [[UIImageView alloc] initWithImage:[UIImage imageNamed:#"yorCheckmark.png"]];
break;
case UITableViewCellAccessoryNone:
self.accessoryView = nil;
break;
default:
break;
}
}
I have googled and done lot of research from my side to find out why the reloadData method on tableview wouldn't work. I checked all the possible solutions like the datasource is set, delegate is set, the tableview is connected to the file's owner.
After all these, when I am trying to reload the tableview, the no. of rows method gets called, but the cell for rowAtIndexPath doesn't get called. Below is the code that I have written. Please let me know, where I am going wrong
- (void)onReservationListSuccess:(NSArray *)rData
{
if ( rData != nil )
{
resList = [[NSArray alloc] initWithArray:rData];
if([resList count] > 0)
{
[self.tripsTableView reloadData];
//[self.tripsTableView beginUpdates];
//[self.tripsTableView reloadSections:[NSIndexSet indexSetWithIndex:0]
// withRowAnimation:UITableViewRowAnimationNone];
//[self.tripsTableView endUpdates];
}
else
{
[tripsTableView reloadData];
[tripsTableView setHidden:YES];
[noTripsLabel setHidden:NO];
}
}
if(fsnNeedsRefresh == YES)
{
[[NSNotificationCenter defaultCenter] postNotificationName:UpdateFSNList object:nil];
fsnNeedsRefresh = NO;
}
}
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
{
return 1;
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
int temp=[resList count];
NSLog(#"The no. of rows are %d", temp);
NSLog(#"Testing Purpose");
NSLog(#"The pnr details of the object is:%#",((TripData *)[resList objectAtIndex:0]).pnrDescription);
return 1;
}
// Customize the appearance of table view cells.
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
NSLog(#"The cell for the row at indexpath is getting called");
static NSString *CellIdentifier = #"TripCellIdentifier";
TripCell *cell = (TripCell *)[tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil)
{
NSArray *nib = [[NSBundle mainBundle] loadNibNamed:#"TripCell" owner:self options:nil];
for(id oneObject in nib)
if([oneObject isKindOfClass:[TripCell class]])
cell = (TripCell *)oneObject;
}
// Set up the cell...
TripData *tripData = (TripData *)[resList objectAtIndex:indexPath.row];
cell.pnrLabel.text = tripData.pnr;
NSLog(#"The cell text is %#",tripData.pnr);
cell.pnrDescriptionLabel.text = tripData.pnrDescription;
NSLog(#"The cell text is %#",tripData.pnrDescription);
cell.pnrTypeLabel.text = tripData.pnrType;
NSLog(#"The cell text is %#",tripData.pnrType);
if(checkInAllowed)
{
cell.checkInButton.tag = indexPath.row;
[cell.checkInButton addTarget:self action:#selector(checkIn:) forControlEvents:UIControlEventTouchUpInside];
}
else
{
[cell.checkInButton setEnabled:NO];
}
return cell;
}
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
// Navigation logic may go here. Create and push another view controller
TripData *tripData = (TripData *)[resList objectAtIndex:indexPath.row];
NSLog(#"%#", tripData.pnr);
if(tripData != nil)
{
TripOverviewViewController *tripOverviewViewController = [[TripOverviewViewController alloc] initWithTrip:tripData];
[self.navigationController pushViewController:tripOverviewViewController animated:YES];
[tripOverviewViewController release];
}
[tableView deselectRowAtIndexPath:indexPath animated:NO];
}
From this part of code I cannot say exactly why it does not work but I'll try to explain how reloadData works.
First, how UITableView works: basically, it's a scrollview. When it is drawn, it checks how many rows it has, then checks their height and from its size and scroll position it decides which rows are currently displayed. Then it asks the delegate to return a UITableViewCell for every displayed row.
When the table is scrolled, it removes the hidden cells from the view hierarchy and adds the cells that have appeared.
And now the tricky part - what does reloadData do? It just removes all the UITableViewCells from the table hierarchy. Nothing more. The actual update is done when the table is drawn for the first time after reloadData.
So, my suggestion is - check that your table is not hidden and check its frame. Also, I see that you are accessing both a property getter self.tripsTableView and an ivar tripsTableView. This is confusing. Do they both return the same?
So I don't know how this is happening, or how to fix it, but I am having an issue of my UISearchDisplayController's plain tableView displaying search results with a grouped cell.
I have a dataSource array with a few names, a tableData array that iterates through the dataSource array and adds any entries that fit the searchText, and then depending on which tableView it is, I reload the tableView with the appropriate dataSource...
Ideas anyone?
Code:
- (NSInteger)tableView:(UITableView *)aTableView numberOfRowsInSection:(NSInteger)section {
// Return the number of rows in the section.
int count = 0;
if(aTableView == self.tableView){
count = [userTableData count]==0?1:[userTableData count];
}else{
count = [tableData count];
}
return count;
}
- (NSString *)tableView:(UITableView *)tableView titleForHeaderInSection:(NSInteger)section {
return #"Users";
}
- (UITableViewCell *)tableView:(UITableView *)tView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
static NSString *CellIdentifier = #"CellIdentifier";
// Dequeue or create a cell of the appropriate type.
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil) {
cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier] autorelease];
cell.accessoryType = UITableViewCellAccessoryNone;
}
if(tView == self.tableView){
if([userTableData count] == 0){
cell.textLabel.text = #"Please select a user";
}else{
cell.textLabel.text = [userTableData objectAtIndex:indexPath.row];
}
}else{
cell.textLabel.text = [tableData objectAtIndex:indexPath.row];
}
return cell;
}
And then as the search is entered, matching strings are added to the tableData array
assign tags to the UITableView and hide the grouuped tableView while searching
In the documentation for UISearchDisplayController about the searchResultsTableView property, it says
Discussion:
This method creates a new table view if one does not already exist.
So what you could try is create your own UITableViewwhen you set up the UISDC, explicitly making it plain:
UITableView *searchTableView = [[UITableView alloc] initWithFrame:CGRectZero
style:UITableViewStylePlain];
searchDisplayController.searchResultsTableView = searchTableView;
I have a very simple application with a UITableViewController. Upon EDITING, I am trying to slide a row into position 0 of the first section. The new row should have an INSERT editing style while the existing row should have a DELETE style.
I've overridden the following 4 methods:
// Customize the number of rows in the table view.
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
if (self.editing && section == 0) {
return2;
}
return 1;
}
- (UITableViewCellEditingStyle)tableView:(UITableView*)tableView
editingStyleForRowAtIndexPath:(NSIndexPath*)indexPath {
int section = indexPath.section;
int row = indexPath.row;
if (self.editing && section == 0 && row == 0) {
return UITableViewCellEditingStyleInsert;
}
return UITableViewCellEditingStyleDelete;
}
- (void)setEditing:(BOOL)editing animated:(BOOL)animated {
[super setEditing:editing animated:animated];
NSIndexPath *ip = [NSIndexPath indexPathForRow:0 inSection:0];
[self.tableView beginUpdates];
if (editing) {
[self.tableView insertRowsAtIndexPaths:[NSArray arrayWithObject:ip]
withRowAnimation:UITableViewRowAnimationLeft];
} else {
[self.tableView deleteRowsAtIndexPaths:[NSArray arrayWithObject:ip]
withRowAnimation:UITableViewRowAnimationFade];
}
[self.tableView endUpdates];
}
// Customize the appearance of table view cells.
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
static NSString *CellIdentifier = #"ClientsControllerCell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil) {
cell = [[[UITableViewCell alloc ] initWithStyle:UITableViewCellStyleValue1reuseIdentifier:CellIdentifier] autorelease];
}
int section = indexPath.section;
int row = indexPath.row;
if (self.editing && section == 0 && row == 0) {
cell.textLabel.text = #"Add Me";
cell.detailTextLabel.text = #"Detail text";
} else {
cell.textLabel.text = #"Test me";
cell.detailTextLabel.text = #"Detail text";
}
return cell;
}
But as soon as I go into EDIT mode, "both" cells end up with an editing style of UITableViewCellEditingStyleInsert.
If I change my logic and append the new cell to the END - then it correctly draws the cells with a DELETE style and the new cell get's an INSERT.
Either way, tableView:editingStyleForRowAtIndexPath gets invoked 4 times. In fact, if I insert the new cell into section:0 row:0, this method gets called with section:row 0:0, 0:1, 0:0, 0:0. Whereas if I append the new cell into section: row:1, this method gets called with section:row 0:0, 0:1, 0:0, 0:1.
What am I missing? I should be able to insert a row and catch it right? For some reason, I can't see section=0 row=1 come through a second time.
-Luther
There's another question on StackOverflow that appears to ask essentially the same thing: SO 1508066.
The answer there claims it's nonstandard to put the Insert row at the top; it should go at the bottom instead. I'm not sure I agree with that contention, but it's certainly the path of least resistance.