UITableView单元格中的UISwitch


82

如何UISwitchUITableView单元格上嵌入?可以在设置菜单中看到示例。

我当前的解决方案:

UISwitch *mySwitch = [[[UISwitch alloc] init] autorelease];
cell.accessoryView = mySwitch;

3
What's wrong with the current way you are doing it?
MobileMon

Answers:


193

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" );
}

1
Instead of MY_SWITCH_CELL should be the corresponding cell number I think. Nice all around solution!
testing

1
@Jesse 'aCell.accessoryView = switchView;' is exactly equivalent to '[aCell setAccessoryView:switchView];'. Do you have some reason to avoid the dot-notation?
zpasternack

1
Thanks 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!
Nitin Alabur

2
How know the index of the switch selected?
doxsi

2
@doxsi switchView.tag = indexPath.row for detect which row switch Changed for swift
Nazmul Hasan

10

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.


8
if (indexPath.row == 0) {//If you want UISwitch on particular row
    UISwitch *theSwitch = [[UISwitch alloc] initWithFrame:CGRectZero];
    [cell addSubview:theSwitch];
    cell.accessoryView = theSwitch;
}

Why do you use initWithFrame? Why do you use addSubview? switch can't be used as a variable name.
testing

Sorry for the switch name. I had some code.. I just changed variable name in it.
k-thorat

It worked for me. Effective solution with less code.
Kenan Karakecili

2
I 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.
johnnieb

2

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.


I'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

1

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
}

0

for swift users

override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
        let cell = UITableViewCell(style: .default, reuseIdentifier: "TableIdentifer")
        let switch = UISwitch()
        cell.accessoryView = switch 
}
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.