将动画构建到UITableView的子类中

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了将动画构建到UITableView的子类中相关的知识,希望对你有一定的参考价值。

我创建了一个我非常喜欢的表视图 - 它在委托函数tableView(_ tableView: UITableView, willDisplay cell: UITableViewCell, forRowAt indexPath: IndexPath)中播放了一些不错的动画。

麻烦的是,我找不到在我的代码库中的其他地方复制该行为的方法,而无需复制并粘贴委托函数中的代码并违反DRY。我希望能够从一个地方调整项目中所有tableviews的动画参数。

  1. 首先,我尝试编写UITableView的子类,但这并不好,因为动画是在委托函数中指定的。您可以使子类成为自己的委托并定义所需的行为,但是其所有其他委托函数都不可用于其包含的视图。
  2. 我考虑编写一个继承自UITableViewDelegate的协议,但是你必须重新实现协议中的每个tableview委托函数,即使其中只有一个是不同的。
  3. 我想过试图调用willDisplayCell函数,但我不确定它是否会起作用,如果我远离它,我真的不想乱七八糟。

我怎么能把这样的东西拉下来?在这个非常具体的情况下,以及更普遍的OOP意义上,想要为委托函数提供默认行为而不必将类设置为自己的委托?

编辑:这不是你可以真正拍照的东西,但仍然是截图请求。 enter image description here

答案

您不应该是UITableView的子类,也不应该是swizzle,也不应该扩展委托协议。

我要做的是编写一个实现和包装委托方法的类。这个类可以拥有它自己的委托,但我宁愿给它封闭来调用。

class TableViewDelegate: UITableViewDeleagte {
    var willDisplayCell: ((UITableView, UITableViewCell, IndexPath) -> Void)?
    let animator: Animator
    weak var tableView: UITableView? {
        didSet {
            tableView?.delegate = self
        }
    }
    init(tableView: UITableView, animator: Animator) {
        self.animator = animator
    }

    func tableView(_ tableView: UITableView, willDisplay cell: UItableViewCell, forRowAt indexPath: IndexPath ) {
        animator.animate(cell)
        willDisplayCell?(tableView, cell, indexPath)
    }
}

一个完整的例子:

protocol AnimatorType {
    func animate(view: UIView)
}


class Animator: AnimatorType {
    func animate(view: UIView) {
        view.transform = CGAffineTransform(translationX: -30, y: 0)

        UIView.animate(withDuration: 0.3, animations: {
            view.transform = CGAffineTransform.identity
        })
    }
}

class TableViewDataSource:NSObject, UITableViewDataSource {

    let data = Array(0 ..< 30).map{ $0 * $0 }
    init(tableView: UITableView) {
        self.tableView = tableView
        super.init()
        tableView.dataSource = self
    }

    weak var tableView: UITableView?

    func numberOfSections(in tableView: UITableView) -> Int {
        return 1
    }

    func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        return data.count
    }


    func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
        let cell = tableView.dequeueReusableCell(withIdentifier: "Cell1", for: indexPath)
        let v = data[indexPath.row]
        cell.textLabel?.text = "(v)"

        return cell
    }

    func object(at indexPath: IndexPath)  -> Int{
        return self.data[indexPath.row]
    }
}


class TableViewDelegate:NSObject, UITableViewDelegate {

    var willDisplayCell: ((UITableView, UITableViewCell, IndexPath) -> Void)?
    var didSelectCell: ((UITableView, IndexPath) -> Void)?

    let animator: AnimatorType
    weak var tableView: UITableView?

    init(tableView: UITableView, animator: AnimatorType) {
        self.tableView = tableView
        self.animator = animator
        super.init()
        tableView.delegate = self

    }

    private var highestIndexPath = IndexPath(row: -1, section: 0)

    func tableView(_ tableView: UITableView, willDisplay cell: UITableViewCell, forRowAt indexPath: IndexPath ) {
        if indexPath.row > highestIndexPath.row {
            animator.animate(view: cell)
            highestIndexPath = indexPath

        }
        willDisplayCell?(tableView, cell, indexPath)
    }

    func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
        didSelectCell?(tableView, indexPath)
    }
}


class ViewController: UIViewController {

    var tableViewDataSource: TableViewDataSource?
    var tableViewDelegate: TableViewDelegate?
    let animator = Animator()

    @IBOutlet weak var tableView: UITableView!

    override func viewDidLoad() {
        super.viewDidLoad()
        self.tableViewDataSource = TableViewDataSource(tableView: tableView)
        self.tableViewDelegate = TableViewDelegate(tableView: tableView, animator: animator)

        self.tableViewDelegate?.didSelectCell = {
            [weak self] tableView, indexPath in
            guard let `self` = self else { return }
            print("selected: (self.tableViewDataSource!.object(at: indexPath))")
        }
    }
}
另一答案

创建UIViewController子类所有动画tableViews继承自:

class BaseAnimatedTableViewController: UIViewController, UICollectionViewDelegate  {
    var tableView: UITableView!  

    override func viewDidLoad() {
        super.viewDidLoad()
        tableView = UITableView
        //setupTableView
        tableView.delegatge = self
    }  
    //override delegate methods, that all subclasses should share
}

并为每个动画tableView子类化:

class AnimatedTableView1: BaseAnimatedTableViewController, UITableViewDataSource {
       ...
}

class AnimatedTableView2: BaseAnimatedTableViewController, UITableViewDataSource {
       ...
}

你当然也可以继承UITableViewController而不是UIViewController

以上是关于将动画构建到UITableView的子类中的主要内容,如果未能解决你的问题,请参考以下文章

Java中代码的执行顺序

继承中代码的执行顺序

java中代码执行顺序

UITableView reloadData 在编辑和保留动画时

layui当点击增加的时候,将form中的值获取的添加到table行中代码

Tutorial中代码的区别及不同效果