在UITableViewCell上实现选择和突出显示动画的正确方法是什么?

时间:2019-04-15 06:00:10

标签: ios swift uitableview animation

我正在尝试使用自定义动画为选择状态和突出显示状态编写UITableViewCell编码。我已经覆盖了setSelected:animated:setHighlighted:animated:方法。但是,这两个方法总是用animated:false来调用。因此,我无法确定系统是在调用方法(在表视图清除选择时)还是在用户点击时。现在,对于高亮显示,我可能只是假定它总是由用户调用,因为我没有找到其他任何仅以编程方式高亮显示单元格的方法。对于setSelected:animated:,我必须知道是否要设置动画。起初,我在点击单元格时一开始找不到正在调用setSelected:animated:的内容,因为即使在覆盖每个UITableViewDelegate方法而未调用supersetSelected:animated:的情况下,从某个地方接到电话。

搜索几天后,我使用料斗反汇编器反汇编了UIKitCore.framework,发现setSelected:animated:实际上是由touchesEnded:event:方法调用的。实际上,实际上有一个内部setSelected:方法,默认情况下会使用setSelected:animated:来调用false。而且,由于没有文档化的api只能让您突出显示一个单元格(不进行选择),并且在内部,setHighlighted:animated:总是用false来调用,所以拥有animated的目的是什么该方法签名中的参数?

我没有找到很多例子。我所发现的涉及手动调用tableView.select:rowAtIndexPath:animated的{​​{1}}可能是animated:truedidSelectRow。感觉很hacky,因为它两次调用willSelectRow

我确信我不是第一个实现自定义动画以突出显示和选择UITableViewCell的人。

更新:

到目前为止,这是我已经实现的,即使感觉很黑,它仍然可以工作。

setSelected:animated:

2 个答案:

答案 0 :(得分:1)

我曾经在collectionview的不同单元中有一张图片。

    let imageView: UIImageView = {
    let iv = UIImageView()
    iv.image = UIImage(named: "icon1")?.withRenderingMode(.alwaysTemplate)
    iv.tintColor = UIColor.rgb(red: 91, green: 14, blue: 13)
    return iv
}()
// Highlighted when pressed
override var isHighlighted: Bool {
    didSet {
        imageView.tintColor = isHighlighted ? UIColor.white : UIColor.rgb(red: 91, green: 14, blue: 13)
    }
}
// When selected
override var isSelected: Bool {
    didSet {
        imageView.tintColor = isSelected ? UIColor.white : UIColor.rgb(red: 91, green: 14, blue: 13)
    }
}

也许这给你一个主意。

答案 1 :(得分:0)

我得出的结论是,UITableView上确实没有API可以像选择一样以编程方式突出显示使用UITableViewCell在单元实例上调用setHighlighted:animated:。在使用animated:true查看UITableViewUITableViewCell的反汇编代码后,可以确认这一点。

通常,HoppersetHighlighted:animated:都是由setSelected:animated:触摸处理程序中的animated:false调用的。有两个内部API函数UIViewsetHighlighted:,它们在内部传递setAnimated:,类似于以下内容:

animated: false

覆盖触摸处理程序不是一个合适的解决方案,因为func setSelected(_ selected: Bool) { setSelected(selected, animated: false) } func setHighlighted(_ highlighted: Bool) { setHighlighted(highlighted, animated: false) } func touches...(...) // the touch handlers { // setSelected(selected) // setHighlighted(highlighted) } 实现中发生了许多其他事情。如果跳过它们,则可能会损坏单元的内部状态。但是,当您调用super或任何其他触摸处理程序时,选择和突出显示方法将使用super.touchesBegan进行调用。

此外,从Apple's documentation开始,如果您决定覆盖所有触摸处理程序,那么似乎应该覆盖所有触摸处理程序。

  

如果您在不调用super的情况下重写此方法(通常使用的模式),则即使您的实现不执行任何操作,也必须重写其他方法来处理触摸事件。

我的解决方案

animated: false

您必须从这些处理程序返回func tableView(_ tableView: UITableView, willSelectRowAt indexPath: IndexPath) -> IndexPath? { tableView.selectRow(at: indexPath, animated: true, scrollPosition: .none) return indexPath } func tableView(_ tableView: UITableView, willDeselectRowAt indexPath: IndexPath) -> IndexPath? { tableView.deselectRow(at: indexPath, animated: true) return indexPath } ,否则,将不会调用委托方法。但是,这意味着您现在将两次调用indexPath。可以通过使用setSelected:animated:来防止这种情况,如下所示。

guard

要设置高光动画,请使用以下命令:

override func setSelected(_ selected: Bool, animated: Bool) {
    guard isSelected != selected else {
        return
    }
    if animated {}
}

但是,这留下了最后一个漏洞,即func tableView(_ tableView: UITableView, shouldHighlightRowAt indexPath: IndexPath) -> Bool { let cell = tableView.cellForRow(at: indexPath) // there is no api on tableview to highlight the cell. // so you must invoke highlight directly on the cell. cell?.setHighlighted(true, animated: true) return true } override func setHighlighted(_ highlighted: Bool, animated: Bool) { guard isHighlighted != highlighted else { return } if animated {} } 时,您实际上并不知道是否对其进行动画处理。您可以在单元格中保留局部变量以保持其跟踪。