iOS UITableViewCell setSelected:animated:总是动画= NO

时间:2015-06-09 14:22:26

标签: ios objective-c uitableview animation

我正在尝试制作自己的选择动画。我已经创建了UITableViewCell的子类。我用-setSelected:animated:方法做我的选择动画。当您通过点击它们来选择或取消选择单元格时,它可以按预期工作。问题是在滚动期间也会看到动画,因为在每个单元格出现之前会调用-setSelected:animated:。这就是重用细胞机制的工作方式,我明白了。我不能得到的是它总是用动画= NO来调用这个方法,无论是点击还是滚动。这对我来说似乎是一个逻辑错误。我推测当你点击它们时应该选择带有动画的单元格,当重复使用单元格出现时,它没有动画。除了手动调用之外,animated参数是否曾被用于任何地方?这是我的代码:

- (void)setSelected:(BOOL)selected animated:(BOOL)animated {

    BOOL alreadySelected = (self.isSelected) && (selected);
    BOOL alreadyDeselected = (!self.isSelected) && (!selected);

    [super setSelected:selected animated:animated];

    if ((alreadySelected) || (alreadyDeselected)) return;

    NSLog(@"Animated selection: %@", animated ? @"YES" : @"NO");

    NSTimeInterval duration;

    if (animated) {

        duration = 0.25;

    } else {

        duration = 0.0;

    }

    [CATransaction begin];
    [CATransaction setAnimationDuration:duration];

    if (selected) {

        //layer properties are changed here...


    } else {

        //layer properties are changed here... 

    }


    [CATransaction commit];


}

这总是没有动画。 我无法想到任何其他如此简单的方法来处理自定义选择。在控制器中实现-didSelectRow方法似乎更糟糕,并且在滚动期间没有调用它,因此重用的单元格将出现在错误的状态。知道如何解决这个问题吗?

更新

我找到了一个临时解决方案:

#pragma mark - Table View Delegate 

- (NSIndexPath *)tableView:(UITableView *)tableView willSelectRowAtIndexPath:(NSIndexPath *)indexPath {

    UITableViewCell *cell = [tableView cellForRowAtIndexPath:indexPath];
    [cell setSelected:YES animated:YES];   
    return indexPath; 
}


- (NSIndexPath *)tableView:(UITableView *)tableView willDeselectRowAtIndexPath:(NSIndexPath *)indexPath {

    UITableViewCell *cell = [tableView cellForRowAtIndexPath:indexPath];
    [cell setSelected:NO animated:YES];

    return indexPath;      
}

确实有效,但我不喜欢它。 TableView的代表必须知道一些关于选择的事实并且它不是全部包含在一个地方这一事实让我感到很烦恼。在录制行时会调用-setSelected两次 - 有和没有动画。

3 个答案:

答案 0 :(得分:3)

这就是表视图的设计方式。选择它时会立即突出显示,因此不需要动画。但是,当您弹回到表视图时,您将(无论如何)看到表视图单元格取消选择动画。您可以在-viewWillAppear:override:

中使用此代码来查看
[self.tableView deselectRowAtIndexPath:[self.tableView indexPathForSelectedRow] animated:animated]

如果您使用UITableViewControllerclearsSelectionOnViewWillAppear属性为YES,则会自动发生。

如果您想要不同的行为,则需要自己编写代码。如果您在此处发布的代码符合您的喜好,请保留它。您还可以修改单元格子类,始终将YES传递给-setSelected:animated:方法覆盖中的超类。

答案 1 :(得分:0)

虽然在讨论中迟到了,但这是一个简单的调整,可以添加到您的单元格代码中:

override func touchesEnded(_ touches: Set<UITouch>, with event: UIEvent?) {
    super.touchesEnded(touches, with: event)
    // Whatever you need to do here
    DispatchQueue.main.asyncAfter(deadline: .now() + 100.milliseconds) { self.setSelected(false, animated: true) }
}

使用touchesEnded代替setSelected可以解决这个问题,无论是在iPad还是iPhone上。

答案 2 :(得分:0)

我找到了一个使用prepareForReuse方法的解决方法,每次在重用单元格之前调用该方法:

class MyTableViewCell: UITableViewCell {

private var shouldAnimate = false

override init(style: UITableViewCellStyle, reuseIdentifier: String?) {
    super.init(style: style, reuseIdentifier: reuseIdentifier)
    selectionStyle = .none
}

required init?(coder aDecoder: NSCoder) {
    fatalError("init(coder:) has not been implemented")
}

override func prepareForReuse() {
    shouldAnimate = false
}

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

    if shouldAnimate {
        //your animation
    }
    else {
        shouldAnimate = true
    }
}

希望它有所帮助。