我有一个UITableViewCell子类,该子类具有通过代码创建的自定义子视图。现在的问题是我正在尝试使UITableView的滚动减少跳动的

这是设置方法。

  • CustomSubview是通过代码
  • 创建的UIView
  • BasePostCellUITableViewCellUITableViewCell子类,用作其他一些单元格的基础
  • UserPostCellTextPostCellDiscussionPostCellBasePostCell子类,它们是使用xib s制作的,到目前为止,由于我不知道是否可以将xib继承到另一个xib,我只是使用viewWithTagawakeFromNib将子视图连接到各自变量,您将在
  • 下面的示例代码中看到
  • 所有这些都是使用NSLayoutConstraints设置的,从我读取/研究的内容来看,这比我创建视图的穿透代码然后手动计算每个单元格的高度和宽度要慢得多。如果可以的话,我会做,但现在我没有这样做的奢侈,因为实际代码库中大约有20多个不同的单元。 (这只是示例代码)

  • 我想以某种方式更改的类是CustomSubviewBasePostCell;或者,如果有更好的方法,请告诉我。

    这是我的代码

    该模型
    class Post {
        var type: PostType = .text
        var text: String = ""
        var title: String = ""
        var displayPhoto: String?
    
        // ... there are other attributes here
    
        enum PostType {
            case text, user, discussion
        }
    }
    

    基类
    class CustomSubview: UIView {
        lazy var likeButton: UIButton = {
            let button = UIButton()
            button.translatesAutoresizingMaskIntoConstraints = false
            button.backgroundColor = .black
            button.titleLabel?.font = UIFont(face: .helveticaNeue, style: .regular, size: 14) // this is a helper function of mine
            button.setTitleColor(UIColor.white, for: .normal)
            button.setTitleColor(UIColor.gray, for: .selected)
            return button
        }()
    
        // The rest are more or less the same as how likeButton is created
        // the most important part is `translatesAutoresizingMaskIntoConstraints`
        // should be set to true since I use `NSLayoutConstraints`
        lazy var commentButton: UIButton = { ... }()
        lazy var shareButton: UIButton = { ... }()
        lazy var followButton: UIButton = { ... }()
        lazy var answerButton: UIButton = { ... }()
    
        func configure(withType type: PostType) {
    
            // I don't know if this is the right way to do this
            self.subviews.forEach { $0.removeFromSuperview() }
    
            switch type {
            case .text:
                [ self.likeButton, self.commentButton, self.shareButton ].forEach { self.addSubview($0) }
    
                // constraints code block
                // code goes something like this
                self.addConstraints(NSLayoutConstraint.constraints(
                    withVisualFormat: "H:|-0-[btnLike(==btnComment)]-0-[btnComment]-0-[btnShare(==btnComment)]-0-|",
                    options: NSLayoutFormatOptions(),
                    metrics: nil,
                    views: ["btnLike": self.likeButton,
                            "btnComment": self.commentButton,
                            "btnShare": self.shareButton]))
    
            case .user:
                [ self.followButton, self.shareButton ].forEach { self.addSubview($0) }
    
                // insert more constraints code block here
            case .discussion:
                [ self.answerButton, self.commentButton, self.shareButton ].forEach { self.addSubview($0) }
    
                // insert more constraints code block here
            }
        }
    }
    
    class BasePostCell: UITableViewCell {
    
        // ... there are other subviews but
        // only this view is modularly created
        var customSubview: CustomSubview?
    
        override func awakeFromNib() {
            super.awakeFromNib()
    
            self.customSubview = self.viewWithTag(990) as? CustomSubview
        }
    
        func configure(withPost post: Post) {
            self.customSubview?.configure(withType: post.type)
        }
    }
    

    BasePostCell的子类
    class UserPostCell: BasePostCell {
        var imgDisplayPhoto: UIImageView?
    
        override func awakeFromNib() {
            super.awakeFromNib()
    
            self.imgDisplayPhoto = self.viewWithTag(0) as? UIImageView
        }
    
        override func configure(withPost post: Post) {
            super.configure(withPost: post)
            self.imgDisplayPhoto?.image = post.image
        }
    }
    
    class TextPostCell: BasePostCell {
        var lblContent: UILabel?
    
        override func awakeFromNib() {
            super.awakeFromNib()
    
            self.lblContent = self.viewWithTag(1) as? UILabel
        }
    
        override func configure(withPost post: Post) {
            super.configure(withPost: post)
            self.lblContent?.text = post.text
        }
    }
    
    class DiscussionPostCell: BasePostCell {
        var lblContent: UILabel?
        var lblDiscussionTitle: UILabel?
    
        override func awakeFromNib() {
            super.awakeFromNib()
    
            self.lblContent = self.viewWithTag(1) as? UILabel
            self.lblDiscussionTitle = self.viewWithTag(2) as? UILabel
        }
    
        override func configure(withPost post: Post) {
            super.configure(withPost: post)
            self.lblContent?.text = post.text
            self.lblDiscussionTitle?.text = post.title
        }
    }
    

    最后是SampleViewController的实现
    class SomeViewController: UIViewController {
        @IBOutlet var tableView: UITableView!
    
        var posts: [Post] = []
        var heightForPost: [IndexPath: CGFloat] = [:]
    
        override func viewDidLoad() {
            super.viewDidLoad()
    
            // let's just say I initialized the posts
            self.posts = <SomePostsArrayHere>
    
            // ... register nib to tableview codes here.
    
            self.tableView.delegate = self
            self.tableView.dataSource = self
            self.tableView.reloadData()
        }
    
        // ... other implementations
    }
    
    // Here is the delegate and dataSource
    extension SomeViewController: UITableViewDelegate, UITableViewDataSource {
        func numberOfSections(in tableView: UITableView) -> Int {
            return 1
        }
    
        func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
            return self.posts.count
        }
    
        func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
            let post = self.posts[indexPath.row]
    
            var postCell: BasePostCell
    
            switch post.type {
            case .text:
                postCell = tableView.dequeueReusableCell(withIdentifier: "TextPostCell", for: indexPath) as! TextPostCell
            case .user:
                postCell = tableView.dequeueReusableCell(withIdentifier: "UserPostCell", for: indexPath) as! UserPostCell
            case .discussion:
                postCell = tableView.dequeueReusableCell(withIdentifier: "DiscussionPostCell", for: indexPath) as! DiscussionPostCell
            }
    
            postCell.configure(withPost: post)
    
            return postCell
        }
    
        func tableView(_ tableView: UITableView, willDisplay cell: UITableViewCell, forRowAt indexPath: IndexPath) {
            self.heightForPost[IndexPath] = cell.frame.size.height
        }
    
        func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
            return self.heightForPost[indexPath] ?? UITableViewAutomaticDimension
        }
    
        func tableView(_ tableView: UITableView, estimatedHeightForRowAt indexPath: IndexPath) -> CGFloat {
            return 300
        }
    }
    

    最佳答案

    我已经建议使用时间分析器来识别问题代码,但是仍然可以在您的代码中看到一个不可以。

    在配置单元格时,请始终在configure(withType type: PostType)上调用CustomSubview。在这里,您可以删除子视图并“重建”它们。那不是在可重用单元格中应该做的事情-您不想触及它们的视图层次结构,您要做的就是更改其内容,例如,更改标签中的文本,更改imageView中的图像等。否则,您将无法充分利用可重复使用的单元格。

    只需更改BaseClass即可配置子视图层次结构一次,然后在cellForRowAt中仅设置子视图的内容:

    class BasePostCell: UITableViewCell {
    
         // ... there are other subviews but
        // only this view is modularly created
        var customSubview: CustomSubview?
    
        override func awakeFromNib() {
            super.awakeFromNib()
    
            self.customSubview = self.viewWithTag(990) as? CustomSubview
        }
    
        func configure(withPost post: Post) {
            // don't reconfigure the customView view hierarchy here, it gets called everytime cellForRowAt is called
        }
    }
    
    
    class UserPostCell: BasePostCell {
        var imgDisplayPhoto: UIImageView?
    
        override func awakeFromNib() {
            super.awakeFromNib()
    
            // subviews setup just once here, because for the UserPostCell
            // the type of the post will never change
            self.customSubview?.configure(withType: .user)
    
            self.imgDisplayPhoto = self.viewWithTag(0) as? UIImageView
        }
    
        override func configure(withPost post: Post) {
            super.configure(withPost: post)
            self.imgDisplayPhoto?.image = post.image
        }
    }
    
    class TextPostCell: BasePostCell {
        var lblContent: UILabel?
    
        override func awakeFromNib() {
            super.awakeFromNib()
    
            self.customSubview?.configure(withType: .text)
    
            self.lblContent = self.viewWithTag(1) as? UILabel
        }
    
        override func configure(withPost post: Post) {
            super.configure(withPost: post)
            self.lblContent?.text = post.text
        }
    }
    
    class DiscussionPostCell: BasePostCell {
        var lblContent: UILabel?
        var lblDiscussionTitle: UILabel?
    
        override func awakeFromNib() {
            super.awakeFromNib()
    
            self.customSubview?.configure(withType: .discussion)
    
            self.lblContent = self.viewWithTag(1) as? UILabel
            self.lblDiscussionTitle = self.viewWithTag(2) as? UILabel
        }
    
        override func configure(withPost post: Post) {
            super.configure(withPost: post)
            self.lblContent?.text = post.text
            self.lblDiscussionTitle?.text = post.title
        }
    }
    

    10-08 06:03