UISwitch in a UITableView cell
Solution 1
Setting it as the accessoryView is usually the way to go. You can set it up in tableView:cellForRowAtIndexPath:
You may want to use target/action to do something when the switch is flipped. Like so:
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
switch( [indexPath row] ) {
case MY_SWITCH_CELL: {
UITableViewCell *aCell = [tableView dequeueReusableCellWithIdentifier:@"SwitchCell"];
if( aCell == nil ) {
aCell = [[[UITableViewCell alloc] initWithFrame:CGRectZero reuseIdentifier:@"SwitchCell"] autorelease];
aCell.textLabel.text = @"I Have A Switch";
aCell.selectionStyle = UITableViewCellSelectionStyleNone;
UISwitch *switchView = [[UISwitch alloc] initWithFrame:CGRectZero];
aCell.accessoryView = switchView;
[switchView setOn:NO animated:NO];
[switchView addTarget:self action:@selector(switchChanged:) forControlEvents:UIControlEventValueChanged];
[switchView release];
}
return aCell;
}
break;
}
return nil;
}
- (void)switchChanged:(id)sender {
UISwitch *switchControl = sender;
NSLog( @"The switch is %@", switchControl.on ? @"ON" : @"OFF" );
}
Solution 2
You can add a UISwitch or any other control to the cell's accessoryView
. That way it will appear on the right-hand side of the cell which is probably what you want.
Solution 3
if (indexPath.row == 0) {//If you want UISwitch on particular row
UISwitch *theSwitch = [[UISwitch alloc] initWithFrame:CGRectZero];
[cell addSubview:theSwitch];
cell.accessoryView = theSwitch;
}
Solution 4
You could prepare the cell in Interfacebuilder, link it to an IBOutlet of your Viewcontroller and return it when the tableview is asking for the proper row.
Instead, you could create a separate xib for the cell (again with IB) and load it using UINib upon the cells creation.
Finally, you could create the switch programmatically and add it to your cells contentview or accessoryview.
Which one suits you best largely depends on what you like to do. If your tableviews content is fixed (for a settings page etc.) the first two might work well, if the content is dynamic I'd prefer the programmatic solution. Please be more specific in what you would like to do, this would make answering your question easier.
Solution 5
This is a more complete solution where turning off and on happens on the view layer (UITableViewCell) and it forwards the events to the tableView delegate through didSelect
and didDeselect
:
class CustomCell: UITableViewCell {
private lazy var switchControl: UISwitch = {
let s = UISwitch()
s.addTarget(self, action: #selector(switchValueDidChange(_:)), for: .valueChanged)
return s
}()
override func awakeFromNib() {
self.accessoryView = switchControl
self.selectionStyle = .none // to show the selection style only on the UISwitch
}
override func setSelected(_ selected: Bool, animated: Bool) {
super.setSelected(selected, animated: animated)
(self.accessoryView as? UISwitch)?.isOn = selected
}
@objc private func switchValueDidChange(_ sender: UISwitch) { // needed to treat switch changes as if the cell was selected/unselected
guard let tv = self.superview as? UITableView, let ip = tv.indexPath(for: self) else {
fatalError("Unable to cast self.superview as UITableView or get indexPath")
}
setSelected(sender.isOn, animated: true)
if sender.isOn {
tv.delegate?.tableView?(tv, didSelectRowAt: ip)
} else {
tv.delegate?.tableView?(tv, didDeselectRowAt: ip)
}
}
}
And on your delegate
func tableView(_ tableView: UITableView, shouldHighlightRowAt indexPath: IndexPath) -> Bool {
return false // to disable interaction since it happens on the switch
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { // to make sure it is rendered correctly when dequeuing:
// stuff
if isSelected { // stored value to know if the switch is on or off
tableView.selectRow(at: indexPath, animated: true, scrollPosition: .none)
} else {
tableView.deselectRow(at: indexPath, animated: true)
}
// more stuff
}
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
// do your thing when selecting
}
func tableView(_ tableView: UITableView, didDeselectRowAt indexPath: IndexPath) {
// do your thing when deselecting
}
Related videos on Youtube
testing
Updated on July 05, 2022Comments
-
testing almost 2 years
How can I embed a
UISwitch
on aUITableView
cell? Examples can be seen in the settings menu.My current solution:
UISwitch *mySwitch = [[[UISwitch alloc] init] autorelease]; cell.accessoryView = mySwitch;
-
MobileMon over 10 yearsWhat's wrong with the current way you are doing it?
-
-
testing over 13 yearsWhy do you use
initWithFrame
? Why do you useaddSubview
?switch
can't be used as a variable name. -
testing over 13 yearsI'd prefer the programmatic solution (despite it's for a settings page), but I'm also interested how the first two options work. Perhaps you could explain them a little bit in more detail.
-
testing over 13 yearsInstead of MY_SWITCH_CELL should be the corresponding cell number I think. Nice all around solution!
-
k-thorat over 13 yearsSorry for the switch name. I had some code.. I just changed variable name in it.
-
Jesse almost 12 yearshow do you write
aCell.accessoryView = switchView;
with bracket notation? -
zpasternack almost 12 years@Jesse 'aCell.accessoryView = switchView;' is exactly equivalent to '[aCell setAccessoryView:switchView];'. Do you have some reason to avoid the dot-notation?
-
Jesse almost 12 years@Z - Thank you! I don't know why it was giving me such a hard time. I don't have any real reason other than some mild OCD. When I'm coding in objective-c I like to stick to bracket-notation as opposed to switching back and forth. I try to save the dot-notation for when I'm doing web development.
-
Nitin Alabur almost 12 yearsThanks so much for this answer! Adding the switch as a subview messes up the voice over commands. Setting it as accessory view works perfect with voiceover!
-
Kenan Karakecili almost 10 yearsIt worked for me. Effective solution with less code.
-
doxsi over 9 yearsHow know the index of the switch selected?
-
johnnieb over 8 yearsI was able to get to this work by only setting the cell’s accessoryView property. I don’t think adding the switch as a subview is necessary.
-
Nazmul Hasan about 7 years@doxsi
switchView.tag = indexPath.row
for detect which row switch Changed for swift -
Dani over 5 yearsWon't initializing the switch in a local scope kill it and nullify the added target function call?
-
Adam Ware almost 3 yearsThis code works noting that you cant use the variable name "switch" because that's reserved for a Switch statement. So using anything else would be fine "aSwitch" etc.