I have one UIViewController with UITableView inside,above table I have UISegmentControl, when I press on segment control I want to load a UItableCustomeCell, would you please help me in this implementation, I don't know how should I add them in cellForRowAtIndexPath, Since I have 3 different Custom cell
Here is the code
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath
*)indexPath
{
if (indexPath.row == self.segmentedControl.selectedSegmentIndex == Test1) {
MytestsCell *cell = [tableView dequeueReusableCellWithIdentifier:#"MytestsCell"];
if (!cell) {
cell = [[MyBooksCell alloc] initWithStyle:UITableViewCellStyleDefault
reuseIdentifier:#"MytestsCell"];
}
return cell;
}
else if (indexPath.row == self.segmentedControl.selectedSegmentIndex == tests) {
testCell *cell = [tableView dequeueReusableCellWithIdentifier:#"testCell"];
if (!cell) {
cell = [[TestsCell alloc] initWithStyle:UITableViewCellStyleDefault
reuseIdentifier:#"testsCell"];
}
return cell;
}
break;
case 1:
if (indexPath.row == self.segmentedControl.selectedSegmentIndex == PTest) {
PTestsCell *cell = [tableView dequeueReusableCellWithIdentifier:#"PTestsCell"];
if (!cell) {
cell = [[PTestsCell alloc] initWithStyle:UITableViewCellStyleDefault
reuseIdentifier:#"PTestsCell"];
}
return cell;
}
break;
}
I don't want to have 3 of them in one table, each custom cell is for one segment control
Thanks in advance!
One alternative I can think of is to switch the table views data source. But I would not recommend that. You could define a delegate of your data source and ask it for the table view cell for a selected segmented control. But this just moves the problem. I would stick to your approach.
So...here is what I would do. Starting with iOS6, you no longer need to check if your cell is nil after dequeuing from the tableview if you use
- (id)dequeueReusableCellWithIdentifier:(NSString *)identifier forIndexPath:(NSIndexPath *)indexPath
You are guaranteed to get a cell back as long as the identifier exists. Also, it doesn't look like you need to do any additional configuration so something like this should work:
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
NSString *identifier = [NSString stringWithFormat:#"%d", self.segmentedControl.selectedSegmentIndex];
return [tableView dequeueReusableCellWithIdentifier:identifier forIndexPath:indexPath];
}
Edit: I forgot to add, that in order to use this, use numbers that correspond to the segments as the identifier for each cell.
Related
I'm adding subviews with UITableViewCell default type. In this, assume that, I've only 2 rows. At first, when it comes to tableView:cellForRowAtIndexPath: I'll generate a dynamic identifier for each cell based on indexPath.row. So it goes well and create a new cell inside if(cell == nil) condition. I'm adding subviews inside this condition only.
Next, out side that condition, I'm simply updating content of subview by fetching them out of the cell's contentView. This works great.
Problem is here : I'm expanding my cell (on which user tapped). When I do this, it'll go into tableView:cellForRowAtIndexPath: and I'm able to see the same identifier generated before. However, its going inside if(cell == nil) condition.
For a note, I'm checking for that condition like this,
if(!cell) and not if(cell == nil).
Can you guess what is the issue? However in my deep investigation, I found that, it'll only goes inside if(cell == nil) once I expand particular row and not next time for the same row.
Here's the sample :
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
//number of count
return [array count];
}
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath {
//dynamic height will be provided based on content.
return [self heightForRow:indexPath];
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
NSString *cellIdentifier = [NSString stringWithFormat:#"cellIdentifier_%ld", (long)indexPath.row];
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:cellIdentifier];
if(!cell) {
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:cellIdentifier];
[cell setSelectionStyle:UITableViewCellSelectionStyleNone];
[self setupCell:cell forRow:[indexPath row] inTable:tableView];
}
[self updateCell:cell forRow:[indexPath row] inTable:tableView];
return cell;
}
- (void) setupCell:(UITableViewCell *)cell forRow:(NSInteger)row inTable:(UITableView *)tableView {
//setting up view here
}
- (void) updateCell:(UITableViewCell *)cell forRow:(NSInteger)row inTable:(UITableView *)tableView {
//updating view here
}
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
self.expandedIndexPath = ([indexPath compare:self.expandedIndexPath] == NSOrderedSame) ? nil : indexPath;
[tableView beginUpdates];
[tableView reloadRowsAtIndexPaths:#[indexPath] withRowAnimation:UITableViewRowAnimationAutomatic];
[tableView endUpdates];
[tableView scrollToRowAtIndexPath:self.expandedIndexPath atScrollPosition:UITableViewScrollPositionMiddle animated:YES];
}
Hope my issue is clear to you. Please comment if you don't get something or found anything missing here (and I'll update it here) or answer if you know what's the solution to this.
Thanks!
I have a UITableView with one section. All of the cells in that one section have cells that are derived from a subclass of UITableViewCell called PLContactCell.
What I'd like to do is, for the very last row of the table only, not use a PLContactCell. I just want to use a normal UITableViewCell that I can format however I would like. I'd also like to be able to have this cell NOT respond to being tapped.
My initial cellForRowAtIndexPath method is:
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
PLContactCell *cell = [tableView dequeueReusableCellWithIdentifier:[PLContactCell reuseIdentifier]];
if (!cell) {
cell = [PLContactCell reusableCell];
cell.delegate = self;
}
id modelObject = [[sections objectAtIndex:indexPath.section] objectAtIndex:indexPath.row];
if ([modelObject isKindOfClass:[NSString class]]) {
[cell configureWithString:modelObject];
} else {
[cell configureWithUser:modelObject];
}
return cell;
}
EDIT
So I tried created a UITableView cell in the XIB file and added the reuse identifier of "newCell" to it. Then I added this code:
if (indexPath.row == [[sections objectAtIndex:indexPath.section] count] - 1) {
NSString *CellIdentifier = #"newCell";
noFormatCell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
}
This doesn't do anything. My question is, how do I access the last row of the section and how do I make it so that that cell it is not a PLContactCell but a UITableView Cell.
If it's always at the end, you might consider using the footer view of the UITableView. You can then keep some extra logic out of your UITableViewDataSource.
If it HAS to be as a cell, you'd have to add an extra row count on your last section, then do an if statement check to watch out for it in your -tableView:cellForRowAtIndexPath: implementation. I would strongly urge you try the footer approach, as it's cleaner and way easier to figure out what you were doing a few months/years from now.
Here's some code. Note you'd need to make another section if you are using grouped style in the UITableView.
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
if (section == sections.count - 1) //Looking for last section
{
return [sections objectAtIndex:section].count + 1; //Add one to the last section
}
return [sections objectAtIndex:section].count;
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
NSInteger row = indexPath.row;
if ((sections.count == indexPath.section) && [sections objectAtIndex:indexPath.section].count == indexPath.row)
{
//Here you would create and return your UITableViewCell
}
PLContactCell *cell = [tableView dequeueReusableCellWithIdentifier:[PLContactCell reuseIdentifier]];
if (!cell) {
cell = [PLContactCell reusableCell];
cell.delegate = self;
}
id modelObject = [[sections objectAtIndex:indexPath.section] objectAtIndex:indexPath.row];
if ([modelObject isKindOfClass:[NSString class]]) {
[cell configureWithString:modelObject];
} else {
[cell configureWithUser:modelObject];
}
return cell;
}
I have a list which I have using as a check boxes. I have enable or disable Check mark on row on select. But when I scroll the list its make mark row after every 10 rows.
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
UITableViewCell *oldCell = [tableView cellForRowAtIndexPath:indexPath];
if (oldCell.accessoryType == UITableViewCellAccessoryCheckmark)
{
oldCell.accessoryType = UITableViewCellAccessoryNone;
}
else
{
oldCell.accessoryType = UITableViewCellAccessoryCheckmark;
}
}
UItableView reuses the cell in every scroll so using condition as per accessory type is not a good practice. You can Create an NSMutableArray with selected items and Check as per the Condition below.
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil) {
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:CellIdentifier];
}
if ([selected containsIndex:indexPath.row]) {
[cell setAccessoryType:UITableViewCellAccessoryCheckmark];
} else {
[cell setAccessoryType:UITableViewCellAccessoryNone];
}
// Do the rest of your code
return cell;
}
in didSelectrowAtindexpath method you can Add and remove the Selected items.
Its because UITableView reuses the cell.
So, in the method cellForRowAtIndexPath, you will have to check for a particular cell (of a particular section and row), if it needs to be checked on, provide the accessory type.
If not needed for that cell, provide accessory type as none.
You need to put your logic to set accessory type for cell in cellForRowAtIndexPath, and to identify the cell to mark with check mark you can mark the object in the list in didSelectRowAtIndexPath: or manage an array of selected/unselected objects of the list here.
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
UITableViewCell *selectedCell = [tableView cellForRowAtIndexPath:indexPath];
if ([selectedCell accessoryType] == UITableViewCellAccessoryNone) {
[selectedCell setAccessoryType:UITableViewCellAccessoryCheckmark];
[NSMutableArray addObject:[AnotherMutableArray objectAtIndex:indexPath.row]];
} else {
[selectedCell setAccessoryType:UITableViewCellAccessoryNone];
[NSMutableArray removeObject:[AnotherMutableArray objectAtIndex:indexPath.row]];
}
[tableView deselectRowAtIndexPath:indexPath animated:NO];
}
Also in your viewDidLoad, instantiate you both mutable arrays-
yourmutableArray1 = [[NSMutableArray alloc]init];
yourmutableArray2 = [[NSMutableArray alloc]init];
myaI have this code:
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
if (tableView == firstTableView){
static NSString *CellIdentifier = #"Cell";
UITableViewCell *cell = (UITableViewCell *)[tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if(cell == nil){
cell = [[[UITableViewCell alloc]initWithStyle:UITableViewStylePlain reuseIdentifier:CellIdentifier] autorelease] ;
}
cell.textLabel.text = [myArray objectAtIndex:indexPath.row];
return cell;
}
}
I check if tableview is firsttableview, but it give me a warning because the method haven't a "return" cell, how can I solve?
You only return a cell if the table is firstTableView. Make sure you return a cell for other tables by adding a return statement outside of your conditional.
Your code needs to return a value for all paths through that method. So, if your check for firstTableView fails, you still need to return a valid UITableViewCell from the method. You should probably read the UITableView programming guide - it walks you through proper usage of a tableview.
Is there a way to disable accessory indicators from rows individually? I have a table that uses
- (UITableViewCellAccessoryType)tableView:(UITableView *)tableView accessoryTypeForRowWithIndexPath:(NSIndexPath *)indexPath
{
return UITableViewCellAccessoryDetailDisclosureButton;
}
I need to disable it (remove icon and not trigger a detail disclosure event) for a single row.
I thought this would do it, but has no result. The indicator still appears and it still receives and event on touch.
cell.accessoryType = UITableViewCellAccessoryNone;
That function call 'accessoryTypeForRow..' is depeecated now (from sdk 3.0 +).
Preferred way of setting the accessory type is in 'cellForRowAt..' method
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
static NSString *CellIdentifier = #"SomeCell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil) {
cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:CellIdentifier] autorelease];
}
// customize the cell
cell.textLabel.text = #"Booyah";
// sample condition : disable accessory for first row only...
if (indexPath.row == 0)
cell.accessoryType = UITableViewCellAccessoryNone;
return cell;
}
You can set from storyboard it. You should just set Separator value to 'None'.