我有一个UITableViewCell
子类,该子类具有通过代码创建的自定义子视图。现在的问题是我正在尝试使UITableView的滚动减少跳动的。
这是设置方法。
CustomSubview
是通过代码UIView
BasePostCell
是UITableViewCell
是UITableViewCell
子类,用作其他一些单元格的基础UserPostCell
,TextPostCell
和DiscussionPostCell
是BasePostCell
子类,它们是使用xib
s制作的,到目前为止,由于我不知道是否可以将xib继承到另一个xib,我只是使用viewWithTag
和awakeFromNib
将子视图连接到各自变量,您将在NSLayoutConstraints
设置的,从我读取/研究的内容来看,这比我创建视图的穿透代码然后手动计算每个单元格的高度和宽度要慢得多。如果可以的话,我会做,但现在我没有这样做的奢侈,因为实际代码库中大约有20多个不同的单元。 (这只是示例代码)我想以某种方式更改的类是
CustomSubview
或BasePostCell
;或者,如果有更好的方法,请告诉我。这是我的代码
该模型
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
}
}