以编程方式通过动画更改UISwitch的状态

7

我有一个UITableView,其中包含一些包含UISwitches的单元格:

UISwitch* actSwitch = (UISwitch*)[cell viewWithTag: SWITCH_TAG];
[actSwitch addTarget: self
              action: @selector(actSwitchChanged:) 
    forControlEvents: UIControlEventValueChanged];
BOOL value = [appSettings.lock_when_inactive boolValue];
[actSwitch setOn: value animated:NO];

我还希望重写didSelectRowAtIndexPath:方法以执行相应UISwitch的切换:

- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {

    NSString *cellType = [self typeOfCellForIndexPath:indexPath];
    if ( cellType  == @"CellWithSwitch" )
    {
        UISwitch* actSwitch = (UISwitch*)[[[self tableView] cellForRowAtIndexPath:indexPath ] viewWithTag: SWITCH_TAG];
        BOOL value = [actSwitch isOn];
        [actSwitch setOn:!value animated:YES]; // <-- HERE IS THE PROBLEM
        [self actSwitchChanged: actSwitch];
    }
    else if ( cellType == @"CellWithoutSwitch" )
    {
        // other actions
    }
}

在这两种情况下,无论我是直接点击UISwitch还是通过单击单元格,它都会改变状态并正确调用actSwitchChanged:。但是,如果我单击单元格,则我的UISwitch不会动画翻转从一个状态到另一个状态,而只是在单个时刻更改其状态。
因此,[actSwitch setOn:!value animated:YES]不足以告诉它执行动画吗?
这是我如何设置和调用配置单元格的方式:
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {

    UITableViewCell *cell = nil;
    NSString *EnabledCellIdentifier = [self typeOfCellForIndexPath:indexPath];  
    cell = [tableView dequeueReusableCellWithIdentifier:EnabledCellIdentifier];

    if (cell == nil) 
    {
        cell = [self cellForType:EnabledCellIdentifier];
    }
    [self cofigureCell:cell forIndexPath:indexPath];

    return cell;
}

这是我如何配置单元格的方式:
- (void)cofigureCell:(UITableViewCell*)cell forIndexPath:(NSIndexPath*)indexPath {
    switch ( indexPath.section )
    {
        case 0: 
            // not this
        case 1: 
        {
            switch ( indexPath.row )
            {
                case 0:
                {
                    cell.textLabel.text = @"Limit passwords attempts";
                    UISwitch* actSwitch = (UISwitch*)[cell viewWithTag: SWITCH_TAG];
                    [actSwitch addTarget: self
                                  action: @selector(actSwitchChanged:) 
                        forControlEvents: UIControlEventValueChanged];
                    BOOL value = [appSettings.limit_password_attempts boolValue];
                    [actSwitch setOn: value animated:NO];

                    break;
                }
                //other rows of this section here are being configured
            }
            break;
        }

        case 2: 
        {
            switch ( indexPath.row )
            {
                case 0:
                {
                    cell.textLabel.text = @"Lock when inactive";
                    UISwitch* actSwitch = (UISwitch*)[cell viewWithTag: SWITCH_TAG];
                    [actSwitch addTarget: self
                                  action: @selector(actSwitchChanged:) 
                        forControlEvents: UIControlEventValueChanged];
                    BOOL value = [appSettings.lock_when_inactive boolValue];
                    [actSwitch setOn: value animated:NO];

                    break;
                }
                //other rows of this section here are being configured
            }
            break;
        }
        default:

            break;
    }
}

但当我逐步进行调试并执行此代码时:

[actSwitch setOn:!value animated:YES]; // <-- 这里有问题

只有在[self actSwitchChanged: actSwitch];更改数据模型并调用[self.tableView reloadData];之后,actSwitch 才会更改其状态。
也许原因是我有两个带有 UISwitches 的单元格,它们之间发生了冲突?或者可能有更好的方法从单元格中获取 UISwitch,而不是使用我的代码吗?
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {

    NSString *cellType = [self typeOfCellForIndexPath:indexPath];
    if ( cellType  == @"CellWithSwitch" )
    {
        UISwitch* actSwitch = (UISwitch*)[[[self tableView] cellForRowAtIndexPath:indexPath ] viewWithTag: SWITCH_TAG];
        BOOL value = [actSwitch isOn];
        [actSwitch setOn:!value animated:YES]; // <-- HERE IS THE PROBLEM
        [self actSwitchChanged: actSwitch];
    }
    else if ( cellType == @"CellWithoutSwitch" )
    {
        // other actions
    }
}

你是否检查了从cell子视图中获取的 actSwitch 视图不是 nil?您能提供添加这些开关到单元格的代码吗? - knuku
感谢您的回复,我已经提供了代码。 - zkaje
[actSwitch setOn:!value animated:YES] 对我来说可行,并像其他任何动画一样。适用于任何IBAction或Void语句。 - Sam Spencer
2个回答

8

只需稍微延迟一下,即可调用您的actSwitchChanged函数:

UISwitch* actSwitch = (UISwitch*)[[[self tableView] cellForRowAtIndexPath:indexPath ]  viewWithTag: SWITCH_TAG];
    BOOL value = [actSwitch isOn];
    [actSwitch setOn:!value animated:YES]; // <-- HERE IS THE PROBLEM
[self performSelector:@selector(actSwitchChanged:) withObject:actSwitch afterDelay:0.55];

0

SWIFT 4

创建一个带有委托协议的UITableViewCell子类。我添加了一个标题标签和一个开关,如下所示:

protocol CellWithSwitchDelegate: class {
    func didToggleSwitch(on: Bool)
}

class CellWithSwitchTableViewCell: UITableViewCell {

    @IBOutlet weak var titleLabel: UILabel!
    @IBOutlet weak var toggleSwitch: UISwitch!
    weak var delegate: CellWithSwitchDelegate?

    override func awakeFromNib() {
        super.awakeFromNib()
    }

    override func setSelected(_ selected: Bool, animated: Bool) {
        super.setSelected(selected, animated: animated)
    }

    @IBAction func switchWasToggled(_ sender: UISwitch) {
        delegate?.didToggleSwitch(on: sender.isOn)
    }    

}

在你的UITableViewController中添加委托方法,如下所示:
class UITableViewController: CellWithSwitchDelegate {

    func didToggleSwitch(on: Bool) {
        // This is the delegate function that's called when the switch is toggled
        print("toggled switch")
    }
}

在你的UITableViewController中,将以下内容添加到didSelectRowAtIndexPath:
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
    let cell = tableView.cellForRow(at: indexPath) as! CellWithSwitchTableViewCell
    let settingsSwitch = cell.toggleSwitch!
    didToggleSwitch(on: !settingsSwitch.isOn)
    settingsSwitch.setOn(!settingsSwitch.isOn, animated: true)
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接