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'.
Related
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.
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];
I'm trying to build an UITableView with some long texts inside each cell. Cells are without AccessoryView, except for one cell (the 8th one), that is a sort of button to open a detail view.
Consider this code:
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
{
CGSize size = [[quotes objectAtIndex:indexPath.row] sizeWithFont:16 constrainedToSize:CGSizeMake(self.view.frame.size.width, CGFLOAT_MAX)];
return size.height+20;
}
- (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.lineBreakMode = UILineBreakModeWordWrap;
cell.textLabel.numberOfLines = 0;
cell.textLabel.text = [quotes objectAtIndex:indexPath.row];
if(indexPath.row==7){
[cell setAccessoryType:UITableViewCellAccessoryDetailDisclosureButton];
}
return cell;
}
It works, but the problem is that when I scroll to the bottom of the Table (the 8th is also the last row) and then I go back to the upper side, another AccessoryView is added to a random point (more or less the 3rd cell, but I don't know if it is inside of it or is floating around randomly).
Is it something related to cell reusing by iOS? How can I avoid it?
Thanks in advance.
You have to explicitly set no disclosure button to every cell but the one that you wish to have disclosure. This way when the cell gets reused elsewhere its disclosure indicator is removed:
if(indexPath.row==7){
[cell setAccessoryType:UITableViewCellAccessoryDetailDisclosureButton];
}else{
[cell setAccessoryType:UITableViewCellAccessoryNone];
}
The cell is being reused (as demonstrated by your call to -dequeueReusableCellWithIdentifer).
The answer is to set the cell to wanted defaults after it's been dequeued, or add an else clause to the if statement to handle it.
- (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.lineBreakMode = UILineBreakModeWordWrap;
cell.textLabel.numberOfLines = 0;
cell.textLabel.text = [quotes objectAtIndex:indexPath.row];
// Set to expected default
[cell setAccessoryType:UITableViewCellAccessoryNone];
if(indexPath.row==7){
[cell setAccessoryType:UITableViewCellAccessoryDetailDisclosureButton];
}
return cell;
}
This is due to cell reuse as you surmise. You must explicitly set UITableViewCellAccessoryNone for cells at index paths other than 7.
I'm having an issue in trying to display info in a cell, one on the left and one on the right. I'm aware using initWithStyle with UITableViewCellStyleSubtitle. I use this but it doesn't seem to work.
Here is some sample code:
- (UITableViewCell *)tableView:(UITableView *)ltableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
static NSString *CellIdentifier = #"Account Cell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil) {
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:Cellidentifier];
}
Accounts *account = [self.fetchedResultsController objectAtIndexPath];
cell.textLabel.text = account.name;
cell.detailTextLabel.text = #"Price";
return cell;
}
I can display cell.textLabel.text just fine, however I cannot get the simple "Price" to be displayed. I've tried different things, such as setting the font size of cell.detailTextLabel.
I've also tried UITableViewCellStyleValue1 as some had suggested in older posts.
Threw NSLog after setting to "Price", shows cell.detailTextLabel as null.
Not sure what I'm doing wrong.
Edit: I found this: cell.detailTextLabel.text is NULL
If I remove if (cell == nil) it works...
That check should be in place, so how do you make it work when using the different styles?
When using storyboards and prototype cells, a cell is always returned from the dequeue method (assuming a prototype with that identifier exists). This means you never get into the (cell == nil) block.
In your case the prototype cell is not defined in the storyboard with the subtitle style, so a subtitled cell is never used, and the detail text label does not exist. Change the prototype in the storyboard to have the subtitle style.
Remove all your code just once you try these lines only and check this will work or not.
-(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *CellIdentifier = #"Cell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil) {
cell = [[[UITableViewCell alloc]
initWithStyle:UITableViewCellStyleSubtitle
reuseIdentifier:CellIdentifier]
autorelease];
}
cell.textLabel.text=[Array objectAtIndex:indexPath.row];
cell.detailTextLabel.text=#"Price";
return cell;
}
I see the problem: in your method name, the UITableView variable is named ltableView, not tableView. Change it to tableView.
cell.detailTextLable.text should be cell.detailTextLabel.text. It looks like a simple mis-spelling of label.
All the answers mentioned here are really a workaround i.e. using storyboard.
Here is a way to do it only in code.
Basically instead of registering the identifier for the cell in viewDidLoad do it only once in cellForRowAtIndexPath: method. Also reset cell registered in viewDidLoad __sCellRegistered = 0;
static int _sCellRegistered = 0;
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
UITableViewCell *cell = nil;
if (__sCellRegistered == 0) {
__sCellRegistered = 1;
NSLog(#"register cell");
cell = [[UITableViewCell alloc]initWithStyle:UITableViewCellStyleValue1 reuseIdentifier:#"CellIdentifier"];
[self.tableView registerClass:[UITableViewCell class] forCellReuseIdentifier:#"CellIdentifier"];
};
if (!cell) {
NSLog(#"dequeue");
cell = [tableView dequeueReusableCellWithIdentifier:#"CellIdentifier" forIndexPath:indexPath];
}
I am an iOS newbie. I am using a checkmark to in a UITableView, and storing the checked value in a local database. When I load the app for the first time, I want to set the value of the checkmark depending on which value exists in the db. How would I do that? Presently this is what I do -
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
static NSString *CellIdentifier = #"Cell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil) {
cell = [[[UITableViewCell alloc] initWithFrame:CGRectZero reuseIdentifier:CellIdentifier] autorelease];
}
if ([indexPath compare:self.lastIndexPath] == NSOrderedSame)
{
cell.accessoryType = UITableViewCellAccessoryCheckmark;
}
else
{
cell.accessoryType = UITableViewCellAccessoryNone;
}
// Set up the cell...
NSString *cellValue = [[self countryNames] objectAtIndex:indexPath.row];
cell.textLabel.text = cellValue;
return cell;
}
and then in didSelectRowAtIndexPath -
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
// some stuff
self.lastIndexPath = indexPath;
[tableView reloadData];
}
Are you asking simply how and when to set the checkmark or are you asking how to populate a table from a database (eg Core Data)?
From your code, the only data you represent is in [self countryNames] and it's not clear under what circumstances you'd want the cell to display a checkmark. Whatever that is, just check the condition and set the checkmark when you are configuring your cell for data (after your "Set up the cell..." comment).
Example if you stored the users country and checked that cell:
// get the current country name
NSString *cellValue = [[self countryNames] objectAtIndex:indexPath.row];
// configure the cell
cell.textLLabel.text = cellValue;
UITableViewCellAccessoryType accessory = UITableViewCellAccessoryNone;
if ([cellValue isEqualToString:self.usersCountry]) {
accessory = UITableViewCellAccessoryCheckmark;
}
cell.accessoryType = accessory;
If you have static table data, then you simply need to store the section and row of the selected table view cell. If you have dynamic data, then you will need to store the unique data for that selected cell in the database and compare that with the cell's content on load. When you are loading your cells in cellForRowAtIndexPath:, simply set that cell's accessory to UITableViewCellAccessoryCheckmark as well as set self.lastIndexPath = indexPath for comparison later.
Also, I typically use [indexPath isEqual:self.lastIndexPath] instead of compare:. Doesn't really make a difference either way, just for readability.