UISwitch en una celda UITableView

82

¿Cómo puedo incrustar un UISwitchen una UITableViewcelda? Se pueden ver ejemplos en el menú de configuración.

Mi solución actual:

UISwitch *mySwitch = [[[UISwitch alloc] init] autorelease];
cell.accessoryView = mySwitch;
pruebas
fuente
3
¿Qué hay de malo en la forma actual en que lo está haciendo?
MobileLun

Respuestas:

193

Establecerlo como accesorio de vista suele ser el camino a seguir. Puede configurarlo en tableView:cellForRowAtIndexPath: Es posible que desee utilizar objetivo / acción para hacer algo cuando se activa el interruptor. Al igual que:

- (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" );
}
zpasternack
fuente
1
En lugar de MY_SWITCH_CELL debería ser el número de celda correspondiente, creo. ¡Buena solución general!
prueba el
1
@Jesse 'aCell.accessoryView = switchView;' es exactamente equivalente a '[aCell setAccessoryView: switchView];'. ¿Tiene alguna razón para evitar la notación de puntos?
zpasternack
1
¡Muchas gracias por esta respuesta! Agregar el interruptor como una subvista altera los comandos de voz en off. ¡Configurarlo como vista de accesorios funciona perfectamente con la voz en off!
Nitin Alabur
2
¿Cómo saber el índice del interruptor seleccionado?
Doxsi
2
@doxsi switchView.tag = indexPath.rowpara detectar qué cambio de fila se cambió para rápido
Nazmul Hasan
10

Puede agregar un UISwitch o cualquier otro control a la celda accessoryView. De esa manera, aparecerá en el lado derecho de la celda, que es probablemente lo que desea.

Escalón
fuente
8
if (indexPath.row == 0) {//If you want UISwitch on particular row
    UISwitch *theSwitch = [[UISwitch alloc] initWithFrame:CGRectZero];
    [cell addSubview:theSwitch];
    cell.accessoryView = theSwitch;
}
k-thorat
fuente
¿Por qué lo usa initWithFrame? ¿Por qué lo usa addSubview? switchno se puede utilizar como nombre de variable.
prueba el
Perdón por el nombre del interruptor. Tenía algo de código ... Acabo de cambiar el nombre de la variable.
k-thorat
Funcionó para mí. Solución eficaz con menos código.
Kenan Karakecili
2
Pude llegar a este trabajo configurando solo la propiedad AccessoriesView de la celda. No creo que sea necesario agregar el interruptor como una subvista.
johnnieb
2

Puede preparar la celda en Interfacebuilder, vincularla a un IBOutlet de su Viewcontroller y devolverla cuando la vista de tabla solicite la fila adecuada.

En su lugar, puede crear un xib separado para la celda (nuevamente con IB) y cargarlo usando UINib al crear las celdas.

Finalmente, puede crear el conmutador mediante programación y agregarlo a la vista de contenido o vista de accesorios de sus celdas.

Cuál se adapta mejor a ti depende en gran medida de lo que te gusta hacer. Si el contenido de las vistas de tabla es fijo (para una página de configuración, etc.), los dos primeros podrían funcionar bien, si el contenido es dinámico, preferiría la solución programática. Sea más específico en lo que le gustaría hacer, esto facilitaría la respuesta a su pregunta.

Tostador
fuente
Preferiría la solución programática (a pesar de que es para una página de configuración), pero también me interesa cómo funcionan las dos primeras opciones. Quizás podrías explicarlos un poco más en detalle.
prueba el
1

Esta es una solución más completa donde se apaga y enciende en la capa de vista (UITableViewCell) y reenvía los eventos al delegado de tableView a través de didSelecty 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)
        }
    }
}

Y en tu delegado


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
}
rgkobashi
fuente
0

para usuarios rápidos

override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
        let cell = UITableViewCell(style: .default, reuseIdentifier: "TableIdentifer")
        let switch = UISwitch()
        cell.accessoryView = switch 
}
king_T
fuente