Swift 如何在iOS 11上的单元取消期间重新实现以前在iOS 10上工作的清晰颜色UITableViewCell遮罩效果?

Swift 如何在iOS 11上的单元取消期间重新实现以前在iOS 10上工作的清晰颜色UITableViewCell遮罩效果?,swift,uitableview,ios10,calayer,ios11,Swift,Uitableview,Ios10,Calayer,Ios11,序言 我在iOS 10上有一个工作自定义的UITableViewCelldemission动画。其实施方式如下: 用户按下提交按钮 在UITableViewCell的子视图的索引零处(单元格的contentView下方)创建、定位并插入自定义视图 contentView在帧外设置动画,而自定义视图的alpha设置为1.0 当contentView完全超出框架时,将调用本机UITableView方法deleteRows(位于:[indexPath],带:.top)。UITableViewCell折

序言

我在iOS 10上有一个工作自定义的
UITableViewCell
demission动画。其实施方式如下:

  • 用户按下提交按钮
  • UITableViewCell
    的子视图的索引零处(单元格的
    contentView
    下方)创建、定位并插入自定义视图
  • contentView
    在帧外设置动画,而自定义视图的alpha设置为1.0
  • contentView
    完全超出框架时,将调用本机
    UITableView
    方法
    deleteRows(位于:[indexPath],带:.top)
    UITableViewCell
    折叠,自定义视图在折叠时隐藏在前一个
    UITableViewCell
    后面
  • 该单元(以及它的所有子视图,包括我的自定义视图)将被删除 下面是它工作的缓慢动画:

    注意:
    tableView
    具有清晰的背景色,允许在其后面显示自定义视图(蓝色)。每个单元格都有一个包含单元格所有内容的
    containerView
    containerView
    contentView
    都有清晰的背景色。一切都很好

    问题

    将我的应用程序迁移到iOS 11时,此动画不再正常工作。下面是它不再工作的缓慢动画

    正如您所看到的,自定义视图在单元撤销时覆盖在上一个单元的顶部,而不更改我的代码

    到目前为止的调查

    到目前为止,我已经确定,
    UITableView
    的结构已经发生了变化:

    UITableView
        UITableViewWrapperView
            cell
                custom view
                contentView
                cell separator view
            cell
            cell
            cell
        UIView
        UIImageView  (scroll view indicator bottom)
        UIImageView  (scroll view indicator right)
    
    对此:(
    UITableViewWrapperView
    已被删除)

    关于这个
    UITableWrapperView
    我注意到的一点是,它的层的
    isOpaque
    属性为true,而
    masksToBounds
    属性为false,而
    UITableView
    和所有
    UITableViewCell
    则相反。由于这一观点在iOS 11中被删除,这可能是我产生错误效果的原因。我真的不知道

    编辑:我发现的另一件事是,工作示例中的
    UITableWrapperView
    在其子视图(所有
    UITableViewCell
    s)的零索引处插入了一个神秘的
    UIView
    ,其中属性
    isOpaque
    设置为true,并且它有一个
    compositingFilter
    。动画完成后,该视图随后将被删除。由于在iOS 11中删除了
    UITableWrapperView
    ,因此根据关联,该视图也丢失了

    问题


    首先,有人知道为什么会发生这种行为变化吗?如果没有,是否有其他方法可以更好地实现iOS 10的效果?我想要clear
    UITableViewCell
    s,但在删除时每个单元格后面都会显示一个自定义视图,该视图在删除时会被另一个clear
    UITableViewCell
    s遮挡,如上面的第一个gif示例所示。

    删除行之前,请将要删除的单元格发送到表视图子视图的后面

    tableView.sendSubview(toBack: cell)
    tableView.deleteRows(at: [indexPath], with: .top)
    
    如果没有单元格,可以使用索引路径检索它

    guard let cell = tableView.cell(for: indexPath) else { return }
    
    // ...
    
    这应该与视图层次的调整一起使用

    CardTableViewController.swift

    CardTableViewCell.swift

    卡片。swift


    首先,我不认为缺少
    UITableViewWrapperView
    是一个问题。 这是父视图,父视图不能隐藏子视图

    请注意,问题是哪个单元格模糊了哪个单元格。在第一种情况下,行A遮挡行B,在第二行B遮挡行A(在这种情况下,自定义B单元格具有透明背景)

    看来苹果的细胞之间的关系搞砸了。为了解决这个问题,我会尝试解决这个关系。所以在动画的第二部分开始之前,我会尝试:


    这不应该破坏任何东西(在旧的iOS版本上),并且应该使用iOS 11解决问题

    我花了很多天学习,但都失败了

    iOS10

    deleteRows
    之后,
    TableViewCell
    有一个具有
    compositingFilter
    属性的视图,该值为
    copy
    ,该视图将所有视图隐藏在该属性后面

    我们可以尝试删除
    deleteRows
    时生成的
    TableViewCell
    的子视图。那么iOS 10的行为将类似于iOS 11

    然后我们可以再次尝试将视图(
    UIView()
    )添加到
    TableViewCell
    ,并将
    compositingFilter
    设置为
    copy
    (字符串),它将再次在iOS10中实现

    但是iOS11中的任何操作失败。它将在iOS11中生成黑色背景

    我相信层的行为在iOS11上发生了改变


    TableViewCell
    的背景是透明的时,我们可能不得不考虑暂时放弃在
    ios11
    中使用
    up
    动画。

    在iOS 11上查看应用程序后,我遇到了这样一个问题,问题是从表视图中删除行时的动画:

    很明显,折叠动画是不合适的,因为要删除的行不止一行

    以下是展开/折叠行的责任代码:

    // inserting rows:                
    tableView.beginUpdates()
    tableView.insertRows(at: [IndexPath(row: 4 + count, section: 0), IndexPath(row: 5 + count, section: 0), IndexPath(row: 6 + count, section: 0)], with: .automatic)
    tableView.endUpdates()
    
    // deleting rows:
    tableView.beginUpdates()
    tableView.deleteRows(at: [IndexPath(row: 4 + count, section: 0), IndexPath(row: 5 + count, section: 0), IndexPath(row: 6 + count, section: 0)], with: .automatic)
    tableView.endUpdates()
    
    显然,还有一些代码可以编辑数据源数组


    造成这一问题的原因很简单,就是分配给;我所做的只是将动画更改为“淡入淡出”:

    // inserting rows:                
    tableView.beginUpdates()
    tableView.insertRows(at: [IndexPath(row: 4 + count, section: 0), IndexPath(row: 5 + count, section: 0), IndexPath(row: 6 + count, section: 0)], with: .fade)
    tableView.endUpdates()
    
    // deleting rows:
    tableView.beginUpdates()
    tableView.deleteRows(at: [IndexPath(row: 4 + count, section: 0), IndexPath(row: 5 + count, section: 0), IndexPath(row: 6 + count, section: 0)], with: .fade)
    tableView.endUpdates()
    
    输出已固定为:

    同时

    您可能需要检查以下可能与您的问题相关的问题:

    我找到了
    UITableView的解决方案
    
    @objc protocol CardTableViewCellDelegate {
        func cardTableViewCell(_ cell: CardTableViewCell, didTouchUpInsideCheckmarkButton button: UIButton)
    }
    
    @IBDesignable class CardTableViewCell: UITableViewCell {
    
        // MARK: Outlets
    
        @IBOutlet var checkmarkButton: UIButton?
        @IBOutlet var customView: CardCustomView?
        @IBOutlet var delegate: CardTableViewCellDelegate?
        @IBOutlet var taskTextLabel: UILabel?
    
        // MARK: Properties
    
        var card: Card? {
            didSet {
                updateOutlets()
            }
        }
    
        // MARK: Lifecycle
    
        override func awakeFromNib() {
    
            super.awakeFromNib()
    
            checkmarkButton?.layer.borderColor = UIColor.black.cgColor
        }
    
        override func prepareForReuse() {
    
            super.prepareForReuse()
    
            card = nil
        }
    
        // MARK: Methods
    
        private func updateOutlets() {
    
            checkmarkButton?.isSelected = card?.isDone == true ? true : false
            checkmarkButton?.superview?.transform = .identity
    
            customView?.alpha = 0
            customView?.dayCount = card?.dayCount
    
            taskTextLabel?.text = card?.text
        }
    
        // MARK: Actions
    
        @IBAction func didTouchUpInsideCheckButton(_ sender: UIButton) {
    
            sender.isSelected = !sender.isSelected
    
            delegate?.cardTableViewCell(self, didTouchUpInsideCheckmarkButton: sender)
        }
    }
    
    class CardCustomView: UIView {
    
        // MARK: Outlets
    
        @IBOutlet var countLabel: UILabel?
        @IBOutlet var daysLabel: UILabel?
    
        // MARK: Properties
    
        var dayCount: Int? {
            didSet { 
                updateOutlets()
            }
        }
    
        override func awakeFromNib() {
    
            super.awakeFromNib()
    
            updateOutlets()
        }
    
        // MARK: Methods
    
        private func updateOutlets() {
    
            let count = dayCount.flatMap { $0 } ?? 0
    
            countLabel?.text = "\(dayCount.flatMap { $0 } ?? 0)"
            daysLabel?.text = "Day\(count == 1 ? "" : "s") in a row"
        }
    }
    
    class Card: NSObject {
    
        // MARK: Properties
    
        var dayCount: Int = 0
        var isDone: Bool = false
        var text: String
    
        // MARK: Lifecycle
    
        init(text: String) {
            self.text = text
        }
    }
    
    cell.superview.sendSubview(toBack: cell)
    
    // inserting rows:                
    tableView.beginUpdates()
    tableView.insertRows(at: [IndexPath(row: 4 + count, section: 0), IndexPath(row: 5 + count, section: 0), IndexPath(row: 6 + count, section: 0)], with: .automatic)
    tableView.endUpdates()
    
    // deleting rows:
    tableView.beginUpdates()
    tableView.deleteRows(at: [IndexPath(row: 4 + count, section: 0), IndexPath(row: 5 + count, section: 0), IndexPath(row: 6 + count, section: 0)], with: .automatic)
    tableView.endUpdates()
    
    // inserting rows:                
    tableView.beginUpdates()
    tableView.insertRows(at: [IndexPath(row: 4 + count, section: 0), IndexPath(row: 5 + count, section: 0), IndexPath(row: 6 + count, section: 0)], with: .fade)
    tableView.endUpdates()
    
    // deleting rows:
    tableView.beginUpdates()
    tableView.deleteRows(at: [IndexPath(row: 4 + count, section: 0), IndexPath(row: 5 + count, section: 0), IndexPath(row: 6 + count, section: 0)], with: .fade)
    tableView.endUpdates()