Swift tableView insertRows 在顶部,同时保持正确的索引

2024-02-21

Problem:

我需要顶部填充tableView 以保持现有单元格的内容加载,例如播放视频。

ref.child(live_mode).queryOrderedByKey().queryLimited(toLast: 200).observe(.childAdded, with: {snapshot in

    self.posts.insert(PostFeed(uid: uid , profile_image_url: profile_image_url, profile_name: profile_name, post_id: post_id, post_title: post_title, post_text: post_text, post_type: post_type, youtube_video_url: youtube_video_url, youtube_video_id: youtube_video_id, youtube_image_url: youtube_image_url, time_stamp: time_stamp, like_count: "0"), at: 0)
            
    self.tableView.insertRows(at: [IndexPath.init(row: 0, section: 0)], with: .automatic)

})

上述方法的问题在于,在分配标签时,单元格索引路径都是相同的

extension ChatViewController: UITableViewDelegate, UITableViewDataSource {


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

    func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
        
        if(posts[indexPath.row].post_type == "text"){
            
            let textCell = tableView.dequeueReusableCell(withIdentifier: "TextTableViewCell", for: indexPath) as! TextTableViewCell
            
            textCell.mainContentView.backgroundColor = .appBackgroundColor
            
            let profileImageURL = posts[indexPath.row].profile_image_url
            
            textCell.profileImageView.layer.borderWidth = 1.0
            textCell.profileImageView.layer.masksToBounds = false
            textCell.profileImageView.layer.borderColor = UIColor.white.cgColor
            textCell.profileImageView.layer.cornerRadius = textCell.profileImageView.frame.size.width / 2
            textCell.profileImageView.clipsToBounds = true
            textCell.profileImageView.af_setImage(withURL: URL(string: profileImageURL)!, placeholderImage: avatar_placeholder, filter: nil,  imageTransition: .crossDissolve(0.5), runImageTransitionIfCached: true, completion: nil)
            
            textCell.usernameLabel.text = posts[indexPath.row].profile_name
            textCell.textBodyTextView.text = posts[indexPath.row].post_text
            
            textCell.usernameLabel.font = .sfProMedium(ofSize: 14)
            textCell.usernameLabel.textColor = .systemGray
            textCell.textBodyTextView.font = .sfProSemiBold(ofSize: 15)
            textCell.textBodyTextView.textColor = .label
            
            textCell.shareButton.addTarget(self, action: #selector(shareButtonTap(sender:)), for: .touchUpInside)
            textCell.shareButton.tag = indexPath.row
            
            textCell.elipsesButton.addTarget(self, action: #selector(elipsesButtonTap(sender:)), for: .touchUpInside)
            textCell.elipsesButton.tag = indexPath.row


            return textCell
            
        }else{
            
            print("print loadign cll: ", indexPath.row)
            
            let videoCell = tableView.dequeueReusableCell(withIdentifier: "VideoTableViewCell", for: indexPath) as! VideoTableViewCell
            
            
            videoCell.mainContentView.backgroundColor = .appBackgroundColor
            let profileImageURL = posts[indexPath.row].profile_image_url
            let youtubeImageURL = posts[indexPath.row].youtube_image_url
            let yt_video_id = posts[indexPath.row].youtube_video_id
            
            
            videoCell.profileImageView.layer.borderWidth = 1.0
            videoCell.profileImageView.layer.masksToBounds = false
            videoCell.profileImageView.layer.borderColor = UIColor.white.cgColor
            videoCell.profileImageView.layer.cornerRadius = videoCell.profileImageView.frame.size.width / 2
            videoCell.profileImageView.clipsToBounds = true
            
            videoCell.usernameLabel.text = posts[indexPath.row].profile_name
            videoCell.textBodyTextView.text = posts[indexPath.row].post_title
            
            videoCell.usernameLabel.font = .sfProMedium(ofSize: 14)
            videoCell.usernameLabel.textColor = .systemGray
            videoCell.textBodyTextView.font = .sfProSemiBold(ofSize: 15)
            videoCell.textBodyTextView.textColor = .label
            videoCell.yt_thumbnail_image.isHidden = false
            
            
            let recognizer = UITapGestureRecognizer(target: self, action: #selector(handleYTTap(_:)))
            videoCell.yt_thumbnail_image.tag = indexPath.row
            videoCell.yt_thumbnail_image.isUserInteractionEnabled = true
            videoCell.yt_thumbnail_image.addGestureRecognizer(recognizer)
            recognizer.delegate = self
            recognizer.view?.tag = indexPath.row
            
            videoCell.shareButton.addTarget(self, action: #selector(shareButtonTap(sender:)), for: .touchUpInside)
            videoCell.shareButton.tag = indexPath.row
            
            videoCell.elipsesButton.addTarget(self, action: #selector(elipsesButtonTap(sender:)), for: .touchUpInside)
            videoCell.elipsesButton.tag = indexPath.row
            videoCell.elipsesButton.isUserInteractionEnabled = true
            
            videoCell.logoLoadingImageView.isHidden = true
            
            videoCell.playerView.isHidden = true
            videoCell.playerView.delegate = self
            videoCell.playerView.tag = indexPath.row
            
            videoCell.profileImageView.af_setImage(withURL: URL(string: profileImageURL)!, placeholderImage: avatar_placeholder, filter: nil,  imageTransition: .crossDissolve(0.5), runImageTransitionIfCached: true, completion: nil)
            
           videoCell.yt_thumbnail_image.af_setImage(withURL: URL(string: youtubeImageURL)!, placeholderImage: thumbnail_placeholder, filter: nil,  imageTransition: .crossDissolve(0.5), runImageTransitionIfCached: false, completion: nil)
            
            return videoCell
            
        }
       
        return UITableViewCell()   
    }

OUTPUT:

单元格索引路径:[0, 0] 单元格索引路径:[0, 0] 单元格索引路径: [0, 0] 单元格索引路径:[0, 0] 单元格索引路径:[0, 0] 单元格索引 路径: [0, 0] 单元格索引路径: [0, 0] 单元格索引路径: [0, 0]

正确的方法是什么top loadtableView 通过使用 insertRows 但维护唯一的 indexPath.row 值?

tableView.reloadData() 为我提供了正确的唯一索引,但没有提供顶部加载 tableView 以避免单元格数据刷新(例如在单元格中播放视频)的能力。

伪代码:

func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {

    customCounter = customCounter + 1
    let cellTag = customCounter
    print("cell index tag: ", cellTag)
}

我也尝试过 self.posts.count - 1,但索引在初始加载时未正确显示。当我滚动到底部然后回到顶部时,它们已正确就位。

self.tableView.insertRows(at: [IndexPath.init(row: self.posts.count - 1, section: 0)], with: .automatic)

你打电话时

self.tableView.insertRows(at: [IndexPath.init(row: 0, section: 0)], with: .automatic)

您指定所有索引路径都位于 0,0 - 这就是您在 cellForRow 方法中看到结果的原因。您总是在索引 0 处插入单元格,这是预期的,也是预期的行为。

当您按照您所说的那样调用 reloadData 时,它将重新加载所有单元格,并且您将获得正确的索引。但是,您依赖于当前出列单元格内值的索引路径。这不起作用,因为您不应该在单元格和索引路径之间添加关系。

来自docs https://developer.apple.com/documentation/uikit/uitableview/1614891-dequeuereusablecell :

表视图维护一个 UITableViewCell 对象的队列或列表,这些对象 数据源已标记为可重用。从您的数据调用此方法 当要求为表视图提供新单元格时,源对象。 如果现有单元可用,此方法会使现有单元出列,或者创建一个 使用您之前注册的类或 nib 文件创建新的文件。

这意味着当你这样做时

textCell.shareButton.tag = indexPath.row

您的单元格 shareButton.tag 将包含当前索引路径,但单元格正在被重用并且稍后的某个时刻您将设置一个不代表模型中实际位置的标签(这是您所期望的)。

因此,您不必尝试依赖标签来确定点击了哪个按钮,而是可以依赖该按钮所在的单元格。如果您可以获得该单元格,那么您可以调用indexPathForCell这将为您提供给定单元格的当前索引路径 - 然后您可以使用它来制作模型的地图。

Check 这个答案 https://stackoverflow.com/a/41305872/483375获取更多信息。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

Swift tableView insertRows 在顶部,同时保持正确的索引 的相关文章

随机推荐