为啥我的 UITableView 单元格在滚动时重叠?

Posted

技术标签:

【中文标题】为啥我的 UITableView 单元格在滚动时重叠?【英文标题】:Why do my UITableView cells overlap on scroll?为什么我的 UITableView 单元格在滚动时重叠? 【发布时间】:2020-06-12 21:20:59 【问题描述】:

我以编程方式创建了一个基本的 ios 应用程序(删除了情节提要)。我还创建了一个带有自定义 UITableViewCell 的 UITableView,并以编程方式设置了约束。在我向下滚动表格视图之前,表格视图的行看起来应该是这样的。但是当我滚动时,它们重叠并且事情变得奇怪。

这是滚动之前的样子: click here for image of app before scrolling

这是应用滚动后的样子:click here for image of app after scrolling

我尝试设置行高,并在单元格和表格视图上使用 clipsToBounds 属性。这是管理 UITableView 的视图控制器的一部分代码:

class SocialFeedVC: UIViewController 
    let tableView = UITableView()
    view.addSubview(tableView)
    tableView.delegate = self
    tableView.dataSource = self
    tableView.allowsSelection = false
    tableView.showsVerticalScrollIndicator = false
    tableView.translatesAutoresizingMaskIntoConstraints = false
    tableView.topAnchor.constraint(equalTo: teamSelectorContainer.bottomAnchor, constant: 3.5).isActive = true
    tableView.leadingAnchor.constraint(equalTo: view.leadingAnchor).isActive = true
    tableView.trailingAnchor.constraint(equalTo: view.trailingAnchor).isActive = true
    tableView.bottomAnchor.constraint(equalTo: view.bottomAnchor).isActive = true
    tableView.register(SocialFeedPostCell.self, forCellReuseIdentifier: cellName)


extension SocialFeedVC: UITableViewDelegate, UITableViewDataSource 
    // Define amount of rows in table view
    func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int 
        return feedPosts.count
    

    // Define each cell in table view
    func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell 
        let cell = tableView.dequeueReusableCell(withIdentifier: cellName) as! SocialFeedPostCell
        let feedPost = feedPosts[indexPath.row]
        cell.set(feedPost: feedPost)
        return cell
    


我的表格单元格代码也在下面,但由于采用程序化路线而有点长。随意看看你想要什么。

import UIKit

class SocialFeedPostCell: UITableViewCell 

    let nameLabel = UILabel()
    let postCreationTimeLabel = UILabel()
    let profilePhoto = UIImageView()

    // Needed with programmatic method
    override init(style: UITableViewCell.CellStyle, reuseIdentifier: String?) 
        super.init(style: style, reuseIdentifier: reuseIdentifier)
        configureProfilePhoto()
        configureNameLabel()
        configrePostCreationTimeLabel()
    

    required init?(coder: NSCoder) 
        fatalError("init(coder:) has not been implemented")
    

    // Update view with controller information accordingly
    func set(feedPost: FeedPost) 
        nameLabel.text = feedPost.nameOfPoster
        postCreationTimeLabel.text = feedPost.creationTimestamp
        profilePhoto.image = UIImage(named: feedPost.profilePhoto)

        // Create post depending on type
        if (feedPost.content.type == PostType.text) 
            let contentLabel: UILabel = 
                let label = UILabel()
                label.numberOfLines = 5
                label.font = Probook.paragraph
                label.lineBreakMode = .byTruncatingTail
                let paragraphStyle = NSMutableParagraphStyle()
                paragraphStyle.lineSpacing = 2.5
                paragraphStyle.lineBreakMode = .byTruncatingTail
                let attrString = NSMutableAttributedString(string: feedPost.content.text!)
                attrString.addAttribute(NSAttributedString.Key.paragraphStyle, value: paragraphStyle, range:NSMakeRange(0, attrString.length))
                label.attributedText = attrString
                return label
            ()
            // Add to subview and provide constraints
            addSubview(contentLabel)
            contentLabel.translatesAutoresizingMaskIntoConstraints = false
            contentLabel.topAnchor.constraint(equalTo: postCreationTimeLabel.bottomAnchor, constant: 15).isActive = true
            contentLabel.bottomAnchor.constraint(equalTo: bottomAnchor, constant: -17.5).isActive = true
            contentLabel.leadingAnchor.constraint(equalTo: leadingAnchor, constant: 10).isActive = true
            contentLabel.trailingAnchor.constraint(equalTo: trailingAnchor, constant: -10).isActive = true
        
        else if (feedPost.content.type == PostType.image) 
            // Create image caption
            let imageCaptionLabel: UILabel = 
                let caption = UILabel()
                caption.numberOfLines = 5
                caption.font = Probook.paragraph
                caption.lineBreakMode = .byTruncatingTail
                let paragraphStyle = NSMutableParagraphStyle()
                paragraphStyle.lineSpacing = 2.5
                paragraphStyle.lineBreakMode = .byTruncatingTail
                let attrString = NSMutableAttributedString(string: feedPost.content.imageCaption!)
                attrString.addAttribute(NSAttributedString.Key.paragraphStyle, value: paragraphStyle, range:NSMakeRange(0, attrString.length))
                caption.attributedText = attrString
                return caption
            ()
            // Add to subview and provide constraints
            addSubview(imageCaptionLabel)
            imageCaptionLabel.translatesAutoresizingMaskIntoConstraints = false
            imageCaptionLabel.topAnchor.constraint(equalTo: postCreationTimeLabel.bottomAnchor, constant: 15).isActive = true
            imageCaptionLabel.leadingAnchor.constraint(equalTo: leadingAnchor, constant: 10).isActive = true
            imageCaptionLabel.trailingAnchor.constraint(equalTo: trailingAnchor, constant: -10).isActive = true

            // Create image
            let imageView: UIImageView = 
                let image = UIImage(named: "chase")
                let imageView = UIImageView(image: image)
                imageView.contentMode = .scaleAspectFit
                imageView.clipsToBounds = true
                imageView.layer.masksToBounds = true
                return imageView
            ()
            // Add to subview and provide constraints
            addSubview(imageView)
            imageView.translatesAutoresizingMaskIntoConstraints = false
            imageView.topAnchor.constraint(equalTo: imageCaptionLabel.bottomAnchor, constant: 15).isActive = true
            imageView.heightAnchor.constraint(equalToConstant: 50).isActive = true
            imageView.leadingAnchor.constraint(equalTo: leadingAnchor).isActive = true
            imageView.trailingAnchor.constraint(equalTo: trailingAnchor).isActive = true
            imageView.bottomAnchor.constraint(equalTo: bottomAnchor).isActive = true
        
    

    func configureProfilePhoto() 
        addSubview(profilePhoto)
        profilePhoto.contentMode = .scaleAspectFill
        profilePhoto.translatesAutoresizingMaskIntoConstraints = false
        profilePhoto.widthAnchor.constraint(equalToConstant: 45).isActive = true
        profilePhoto.heightAnchor.constraint(equalToConstant: 45).isActive = true
        profilePhoto.layer.cornerRadius = 25
        profilePhoto.clipsToBounds = true
        profilePhoto.topAnchor.constraint(equalTo: topAnchor, constant: 17.5).isActive = true
        profilePhoto.leadingAnchor.constraint(equalTo: leadingAnchor, constant: 20).isActive = true
    

    func configureNameLabel() 
        addSubview(nameLabel)
        nameLabel.numberOfLines = 0
        nameLabel.adjustsFontSizeToFitWidth = true
        nameLabel.font = Probook.h2
        nameLabel.translatesAutoresizingMaskIntoConstraints = false
        nameLabel.leadingAnchor.constraint(equalTo: profilePhoto.trailingAnchor, constant: 20).isActive = true
        nameLabel.centerYAnchor.constraint(equalTo: profilePhoto.centerYAnchor).isActive = true
    

    func configrePostCreationTimeLabel() 
        addSubview(postCreationTimeLabel)
        postCreationTimeLabel.numberOfLines = 0
        postCreationTimeLabel.adjustsFontSizeToFitWidth = true
        postCreationTimeLabel.font = Probook.timestamp
        postCreationTimeLabel.translatesAutoresizingMaskIntoConstraints = false
        postCreationTimeLabel.topAnchor.constraint(equalTo: nameLabel.bottomAnchor).isActive = true
        postCreationTimeLabel.leadingAnchor.constraint(equalTo: nameLabel.leadingAnchor).isActive = true
    


【问题讨论】:

请附上您的手机号码 已添加单元格代码 不要在集合调用中添加标签...因为当单元格重用时它们不会删除它们...e 【参考方案1】:

它们没有“重叠”。问题是您忘记了单元是重用。因此,以前说“我在发帖”但现在说“Sivan 月”的单元格现在说 both,因为添加新文本时不会删除旧文本。当单元格位于不同行时,您将视图放置在您添加的现有视图上。

【讨论】:

在这种情况下删除以前的文本的常规方法是什么? 哦,你只需要看看你是否已经添加了标签。如果有,请不要再次添加;重复使用您已添加的现有标签。或者,在添加新标签之前始终查找标签并将其删除。只要确保只有一个!对于图像也是如此;不要只是将图像添加到需要它的行中,而是从不需要它的行中删除它。 一个非常简单的方法是实现prepareForReuse 以摆脱一切。现在当set(feedPost:) 出现时,我们从一个空单元格开始。 我在调用 set 之前使用了你的一个想法来删除所有内容 - 就像一个魅力。我只是更改了 set 函数,否则我将使用 prepareForReuse。非常感谢! 干得好!欢迎来到可重复使用细胞的世界! :)

以上是关于为啥我的 UITableView 单元格在滚动时重叠?的主要内容,如果未能解决你的问题,请参考以下文章

UITableview刷新单元格在部分标题下滚动

UITableView 单元格在向下滚动然后备份后消失

uitableview 自定义单元格在向下滚动 uitableview 时丢失其内容

UITableView 选定的单元格在滚动时不会保持选中状态

用于 UITableView 的自定义 XIB 单元格在滚动时卡住/卡住

用户点击编辑按钮时重做 UITableView 布局?