【问题标题】:Multiple Cells for Comments and Reply in a CollectionViewCollectionView 中用于评论和回复的多个单元格
【发布时间】:2019-06-10 11:36:48
【问题描述】:

我有两种不同的单元格类型,一种用于 cmets,另一种用于回复。我试图将它们呈现在相同的collectionView 中,然后可能像这样对它们进行分组:每个具有特定 id 的评论都有它的回复。然而,任何尝试,我都失败了。

你会怎么做?

private var comments = [Comment]()
private var replies = [Reply]()
var items: [Any] = []


    override func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
        return items.count
    }

    override func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
//        let item = items[indexPath.item]

        var item = items[indexPath.item]

        if item is Comment.Type  {

            let cell = collectionView.dequeueReusableCell(withReuseIdentifier: CommentCell.cellId, for: indexPath) as! CommentCell
            cell.comment = items[indexPath.item] as? Comment
            print(item)
            return cell


        } else {
                    let cell = collectionView.dequeueReusableCell(withReuseIdentifier: RepliesCell.cellId, for: indexPath) as! RepliesCell
            cell.reply = items[indexPath.item] as? Reply

                    return cell

        }



    }

    func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, minimumLineSpacingForSectionAt section: Int) -> CGFloat {
        return 0
    }

    func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {
        let item = items[indexPath.item]

        if item is CommentCell.Type {

            let dummyCell = CommentCell(frame: CGRect(x: 0, y: 0, width: view.frame.width, height: 50))
            dummyCell.comment = items[indexPath.item] as? Comment
            dummyCell.layoutIfNeeded()

            let targetSize = CGSize(width: view.frame.width, height: 250)
            let estimatedSize = dummyCell.systemLayoutSizeFitting(targetSize)
            let height = max(40 + 8 + 8, estimatedSize.height)

            return CGSize(width: view.frame.width, height: height)
        } else {
            let dummyCell = RepliesCell(frame: CGRect(x: 0, y: 0, width: view.frame.width, height: 50))
            dummyCell.reply = items[indexPath.item] as? Reply
            dummyCell.layoutIfNeeded()

            let targetSize = CGSize(width: view.frame.width, height: 250)
            let estimatedSize = dummyCell.systemLayoutSizeFitting(targetSize)
            let height = max(40 + 8 + 8, estimatedSize.height)

            return CGSize(width: view.frame.width, height: height)
        }
     }
}

【问题讨论】:

  • 如果我理解正确的话,每个回复都有评论的依赖。如果是,您需要将回复放入 cmets 模型中。
  • 是的回复位于具有评论 ID 值的节点中。我已经有一个回复模型,并希望按原样使用它。
  • 您能否分享 items 对象内部的内容以及您分配它的位置?
  • 请调试代码并在进入collectionviews单元格数函数时检查项目数是否正确
  • 那么你需要分享你分配数组的位置以及如何重新加载collectionView。

标签: ios swift uicollectionview uicollectionviewcell


【解决方案1】:

最佳实践解决方案

创建一个包含回复对象列表的回复模型和评论模型

class Comment {
    var commentId: Int
    var commentText: String
    var replies: [Reply]

    init(commentId: Int, commentText: String, replies: [Reply]) {
        self.commentId = commentId
        self.commentText = commentText
        self.replies = replies
    }
}

class Reply {
    var replyId: Int
    var replyText: String

    init(replyId: Int, replyText: String) {
        self.replyId = replyId
        self.replyText = replyText
    }
}

为评论头创建一个 UICollectionReusableView

class CommentHeader: UICollectionReusableView {

    @IBOutlet weak var commentTextLabel: UILabel!

    override func awakeFromNib() {
        super.awakeFromNib()
        // Initialization code
    }

    func configure(with comment: Comment) {
        commentTextLabel.text = comment.commentText
    }

}

创建一个 UICollectionViewCell 用于回复

class ReplyCell: UICollectionViewCell {

    @IBOutlet weak var replyTextLabel: UILabel!

    override func awakeFromNib() {
        super.awakeFromNib()
        // Initialization code
    }

    func configure(with reply: Reply) {
        replyTextLabel.text = reply.replyText
    }

}

创建一个具有 UICollectionView 和 cmets 数据列表的 CommentsViewController 类

注意header和cell在viewDidLoad方法中注册到collection view中

class CommentsViewController: UIViewController {

    @IBOutlet weak var collectionView: UICollectionView!

    var comments: [Comment] = [Comment]()

    override func viewDidLoad() {
        super.viewDidLoad()

        collectionView.register(UINib(nibName: "CommentHeader", bundle: nil), forSupplementaryViewOfKind: UICollectionElementKindSectionHeader, withReuseIdentifier: "CommentHeaderIdentifier")
        collectionView.register(UINib(nibName: "ReplyCell", bundle: nil), forCellWithReuseIdentifier: "ReplyCellIdentifier")

        comments = getDummyComments(with: 3)
    }

    func getDummyComments(with count: Int) -> [Comment] {

        var comments = [Comment]()
        for i in 1...count {
            comments.append(Comment(commentId: i, commentText: "Comment \(i)", replies: getDummyReplies(with: i)))
        }
        return comments

    }

    func getDummyReplies(with count: Int) -> [Reply] {
        var replies = [Reply]()
        for i in 1...count {
            replies.append(Reply(replyId: i, replyText: "Reply \(i)"))
        }
        return replies
    }
}

最后设置 UICollectionView 数据源和委托方法

extension CommentsViewController: UICollectionViewDataSource {

    // for cell
    func numberOfSections(in collectionView: UICollectionView) -> Int {
        return comments.count
    }

    func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
        return comments[section].replies.count
    }

    func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {

        let replyCell = collectionView.dequeueReusableCell(withReuseIdentifier: "ReplyCellIdentifier", for: indexPath) as! ReplyCell
        replyCell.configure(with: comments[indexPath.section].replies[indexPath.row])
        return replyCell

    }

    // for header
    func collectionView(_ collectionView: UICollectionView, viewForSupplementaryElementOfKind kind: String, at indexPath: IndexPath) -> UICollectionReusableView {

        if kind == UICollectionElementKindSectionHeader {

            let commentHeader = collectionView.dequeueReusableSupplementaryView(ofKind: kind, withReuseIdentifier: "CommentHeaderIdentifier", for: indexPath) as! CommentHeader

            commentHeader.configure(with: comments[indexPath.section])
            return commentHeader
        }

        return UICollectionReusableView()
    }

    func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, referenceSizeForHeaderInSection section: Int) -> CGSize {
        return CGSize(width: collectionView.frame.width, height: 100) // this height is used for the example, you can use self sizing for height
    }

}

extension CommentsViewController: UICollectionViewDelegateFlowLayout {

    func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {

        return CGSize(width: collectionView.frame.width, height: 100) // this height is used for the example, you can use self sizing for height

    }

}

让我们看看 cmets 屏幕:)

【讨论】:

  • 太棒了。我会试一试,然后再回复你。
【解决方案2】:

如果我错了,请纠正我,您正在尝试制作嵌套单元格,并且每个单元格都有一个标题类型的东西,就像 Facebook 一样是评论,对吧!

所以事情是这样的,评论将在每个部分的标题中,回复将在单元格中。所以这样一来,cmets就会出现在每个section的最上方,replies cells充当body。 cmets 需要 numberOfSections 委托,回复需要 numberOfRows 委托。

如果你不明白,问我。

【讨论】:

  • 是的,我正在尝试制作嵌套单元格,但我从未想过要使用标题。我会试一试,然后回到你的答案。谢谢!
  • 这样你可以轻松管理你的数据,我的意思是,每当我遇到这个问题时,我通常都会使用这种方法。所以你也应该试一试。请通知我。
  • 我无法让它工作。请给我一个代码示例,以及我必须实现的每个方法吗?
  • 首先告诉我你能通过故事板制作你的布局吗?
  • 评论和回复
【解决方案3】:

所以我基本上做的是创建一个 PostType 类,这样当我必须渲染某种单元格类型时,我可以切换 cmets 和回复类型。

class PostType {
    enum CommentsTypes {
        case PostType
        case Reply
        case Comment
    }

    var type: CommentsTypes {
        get {
            return .PostType
        }
    }
}

像这样将我的 Comments 和 Replies 类子类化为 PostType:

class Comment: PostType {

   ....

    override var type: CommentsTypes {
        return .Comment
    }
}

class Reply: PostType {

    ....

    override var type: CommentsTypes {
        return .Reply
    }
}

然后我创建了一个 PostType 数组来保存 cmets 和获取后的回复:

 var postsTypes: [PostType] = []

 //after fetching comments and replies 
self.postsTypes.append(contentsOf: comments)
self.postsTypes.append(contentsOf: replies) 

终于确定了

override func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {

        return postsTypes.count
    } 

override func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {

let item = indexPath.item
let post = self.postsTypes[item]

switch post.type  {
case .Comment:
    let comment = post as! Comment
    let cell = collectionView.dequeueReusableCell(withReuseIdentifier: CommentCell.cellId, for: indexPath) as! CommentCell
    cell.comment = comment
    return cell
case .Reply:
    let reply = post as! Reply
    let cell = collectionView.dequeueReusableCell(withReuseIdentifier: RepliesCell.cellId, for: indexPath) as! RepliesCell

    cell.reply = reply

    return cell

default:
    return UICollectionViewCell()
}
}

像魅力一样工作!很高兴我终于找到了我的问题的答案。感谢大家的建议。

【讨论】:

  • 有人有更好的答案吗?
猜你喜欢
  • 2022-01-28
  • 1970-01-01
  • 2018-06-05
  • 1970-01-01
  • 1970-01-01
  • 2019-08-07
  • 1970-01-01
  • 2011-07-05
  • 1970-01-01
相关资源
最近更新 更多