在UITableViewCell

时间:2018-02-23 13:35:10

标签: ios swift uitableview

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

以下是设置方法。

  1. CustomSubview是通过代码
  2. 创建的UIView
  3. BasePostCellUITableViewCellUITableViewCell子类,用作其他一些单元格的基础
  4. UserPostCellTextPostCellDiscussionPostCell是使用BasePostCell生成的xib子类,因为我不知道是否已知有可能以某种方式将xib继承到另一个xib,我只使用viewWithTagawakeFromNib将子视图连接到各自的变量,您将在下面的示例代码中看到
  5. 所有这些都是使用NSLayoutConstraints进行设置的,从我阅读/研究过的内容比我通过代码创建视图然后只需手动计算高度和宽度要慢得多每个细胞。如果可以的话,我想,但是现在我没有这样的奢侈,因为真正的代码库中有大约20多个不同的单元格。 (这只是一个示例代码)
  6. 我想要以某种方式改变的课程是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
        }
    }
    

1 个答案:

答案 0 :(得分:1)

我已经建议使用时间分析器来识别问题代码,但我仍然在代码中看到一个禁忌。

在配置单元格时,您始终在configure(withType type: PostType)上致电CustomSubview。在那里,你删除子视图和&#34;重建&#34;他们。这不是你应该在可重复使用的单元格中做的事情 - 你不想触摸它们的视图层次结构,你想要做的就是改变它们的内容,例如,更改标签中的文本,更改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
    }
}