I use storyboard and Auto Layout. I add UISwitch to my cell with tag 5. When I choose first UISwitch and scroll down I see that other UISwitch is also turned on and if I scroll up my first UISwitch is turned off. How to fix this?
My code:
- (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];
}
UISwitch* switchView = (UISwitch *)[cell viewWithTag:5];
[switchView addTarget:self action:#selector(switchChanged:) forControlEvents:UIControlEventValueChanged];
return cell;
}
This is because UITableView reuse UITableViewCell so one cell can be use more than once in different indexPaths, in this situation its your responsibility to maintain the state of UITableViewCell subViews. Better place to do this is cellForRowAtIndexPath where you are returning cell add logic to make show/hide UISwitch or to select accurate state i.e. on or off, you can keep that flag in dataSource object and then you can check for that flag to make set right state for UISwitch
Try This:
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *CellIdentifier = #"CellSetting";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier forIndexPath:indexPath];
cell.textLabel.text = [self.settingsArray objectAtIndex:indexPath.row];
cell.accessoryType = UITableViewCellAccessoryDisclosureIndicator;
if ([[self.settingsArray objectAtIndex:indexPath.row] isEqualToString:ROW_PRIVATE_BROWSING])
{
self.privateBrowsingSwitch =[[UISwitch alloc]initWithFrame:CGRectMake(cell.frame.size.width-65, 10, 30, 30)];
if (ApplicationDelegate.privateBrowsing)
{
[self.privateBrowsingSwitch setOn:YES animated:YES];
}
[self.privateBrowsingSwitch addTarget:self action:#selector(changeSwitch:) forControlEvents:UIControlEventValueChanged];
[cell addSubview:self.privateBrowsingSwitch];
cell.accessoryType = UITableViewCellAccessoryNone;
}
return cell;
}
Every time cellForRowAtIndexPath is called you have to replace the specific data that needs to be displayed for a cell at that position. This includes things like labels, images and your UISwitch.
This occurs because UITableViews use a small number of cells that are reused.
In cellForRowAtIndexPath add something like this:
switchView.on = [self isSwitchOnForCellAtIndexPath:indexPath]
Then write whatever logic is required to determine if the switch should be on or not.
Related
here i have a table view where i'm adding custom label which stores some
quiz ids from array
where cell.textlabel.text stores quiz names from array
problem:
when i'm selecting first row in didselectRowAtIndexPath
it returns cell.textlabel.tex but for second row it is returning correct value that is
quiz ids
here is code
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *CellIdentifier = #"CellId";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil) {
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier];
}
cell.textLabel.text = [quizname objectAtIndex:indexPath.row];
UILabel *lbl = [[UILabel alloc]init];
lbl.tag=indexPath.row;
[cell addSubview:lbl];
lbl.text = [quizIds objectAtIndex:indexPath.row];
return cell;
}
in did selectrow
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
UITableViewCell *cell = [tableView cellForRowAtIndexPath:indexPath];
UILabel *label = (UILabel *) [cell viewWithTag:indexPath.row];
NSString *qid =label.text;
NSLog(#"%#",qid);
}
i'm getting quid is equal to cell.texlabel.text for firsr row but not in others rows
they are getting quiz ids perfectly
any help most valueble for me
Try using customTableViewCell & add your label inside the customCell. Adding UILabel inside cellForRowAtIndexPath is not a good approach.
I have a tableView, with custom cells.
In each cell i have a UIButton. When i click the button inside the cell i want that cell to highlight, but when i click o the cell i don't want this to happen.
Do you know any way to do this?
thank you
until now i have this code:
- (IBAction)buttonMethod: (id)sender {
UIButton *b = (UIButton *) sender;
UITableViewCell *cell = (UITableViewCell *)[[[sender superview] superview] superview];
cell.selectionStyle = UITableViewCellSelectionStyleBlue;
[cell setSelected:YES animated:YES];
}
but the cell is highlighted also in -didSelectRow.
- (UITableViewCell *)tableView: (UITableView *) tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
static NSString *cellIdentifier = #"CustomCell";
CustomCell *cell = (CustomCell *) [tableView dequeueReusableCellWithIdentifier:cellIdentifier];
NSAssert(cell, #"cell -> nil");
NSDictionary *cellData = [_data objectAtIndex:indexPath.row];
cell.selectionStyle = UITableViewCellSelectionStyleBlue;
[cell populateCellWithData:cellData];
return cell;
}
Use this UITableViewDelegate method:
- (NSIndexPath *)tableView:(UITableView *)tableView willSelectRowAtIndexPath:(NSIndexPath *)indexPath {
return nil;
}
This way, cells can't be selected when the user taps on them, but you can still select them programatically.
Also using
selectRowAtIndexPath:animated:scrollPosition:
on your UITableView , instead of setSelected:animated: on UITableViewCell might be better. Cells can be reused and the selection will probably disappear when it happens.
You have to add following line in tableView delegate method cellForRowATIndexPath.
cell.selectionStyle =- UITableViewCellSelectionStyleNone;
You have to set cell.selectionStyle = UITableViewCellSelectionStyleNone; in cellForRowAtIndexPath method of tableView.
So you can set this style in - (IBAction)buttonMethod: (id)sender. You can add this line at the end. See below:
- (IBAction)buttonMethod: (id)sender {
UIButton *b = (UIButton *) sender;
UITableViewCell *cell = (UITableViewCell *)[[[sender superview] superview] superview];
cell.selectionStyle = UITableViewCellSelectionStyleBlue;
[cell setSelected:YES animated:YES];
cell.selectionStyle = UITableViewCellSelectionStyleNone;
}
Just use UITableViewDelegate like this
-(BOOL)tableView:(UITableView *)tableView shouldHighlightRowAtIndexPath:(NSIndexPath *)indexPath{
return NO;
}
but If I were you, I would change the background color of cell in [buttonMethod:] with UITableViewCellSelectionStyleNone
As soon as the table view gets touched the cell titles (and on-tap actions) disappear. I only use standard table view cells and store the values in an array. After the values disappear the table stays scrollable. Any ideas?
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
NSString *CellIdentifier = #"Cell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil) {
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier];
}
// Configure the cell...
cell.textLabel.text = [[systeme objectAtIndex:indexPath.row] description];
cell.backgroundColor = [UIColor clearColor];
[cell.textLabel setTextColor:[UIColor whiteColor]];
[cell.textLabel setTextAlignment:NSTextAlignmentCenter];
return cell;
}
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
[tableView deselectRowAtIndexPath:indexPath animated:YES];
[[NSNotificationCenter defaultCenter] postNotificationName:#"choseSystem" object:[systeme objectAtIndex:indexPath.row]];
}
You should be sure that the reuse identifier is the same for all cells if you use only one type of cells. You should do something similar to the following in the portion of your code where to retrieve a reusable cell:
NSString *CellIdentifier = [NSString stringWithFormat:#"CellReuseIdentifier", (long)indexPath.section];
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
And make you you set the #"CellReuseIdentifier" in your xib file or your storyboard.
If you would like to use multiple custom cells for a table view you should do something similar to what you're doing, but take into account that reuse identifiers need to be configured for every type of cells.
Hope this helps!
The table view was fine. I just added its view as a subview to another view without keeping reference to the actual UITableViewController. That was the problem.
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 want to know if this control derives from UITableViewController?
If so, how?
Thank you.
This is how you add the UISwitch view to the table cell. (As an accessory)
- (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];
//add a switch
UISwitch *switchview = [[UISwitch alloc] initWithFrame:CGRectZero];
cell.accessoryView = switchview;
[switchview release];
}
cell.textLabel.text = [NSString stringWithFormat:#"%d", indexPath.row];
return cell;
}
yes it is a table view Controller .. Grouped style ... first section has 7 rows
I cannot say for sure if derived or not but i suppose not... you can addView to specific row so you can customize the cell ...deriving tableCell is not mandatory
Not sure what you mean.
If you mean how they have UISwitch in a table cell then its probably a subclass of UITableViewCell that they put a UISwitch in.