简体   繁体   中英

How to load an UITableView from inside UITableViewCell?

Quick explanation before showing some code:

I want to create an architecture where I have Posts, replies to these posts and replies to these replies, etc (with a limit that I can define).

Which each one of the replies being expandable.

I don't know if I take this the right way but I'm thinking about adding a UITableView as a child of my UITableViewCell to show the replies and do it again for the replies to replies, etc.

What I have for now is only a UITableView with all the posts as a reusable cell from a xib. Since I can't add an UITableView and a cell to this xib, I'm stuck.

Here is some code:

Posts UITableView funcs:

func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
        let cell = argumentList.dequeueReusableCell(withIdentifier: "postBox", for: indexPath) as! PostBox
        let currentPost = postListItems[indexPath.row]
        cell.postBoxView.message = currentPost
        return cell
    }

The PostBox file:

import UIKit

class PostBox: UITableViewCell {
    let apiClient = APIClient.sharedInstance
    @IBOutlet weak var postBoxView: PostBoxView!
}

The PostBoxView file:

class PostBoxView: UIView {
    var apiClient = APIClient.sharedInstance
    var repliesOpen: Bool = false
    @IBOutlet var contentView: UIView!
    // Bunch of outlets here
    
    var message: Message! {
        didSet {
            // initializing design stuff here
        }
    }
    
    override init(frame: CGRect){
        super.init(frame: frame)
        self.commonInit()
    }
    
    required init?(coder aDecoder: NSCoder) {
        super.init(coder: aDecoder)
        self.commonInit()
    }
    
    func commonInit(){
        let bundle = Bundle(for: Self.self)
        let nib = UINib(nibName: String(describing: type(of: self)), bundle: bundle)
        nib.instantiate(withOwner: self, options: nil)

        addSubview(contentView)
        contentView.translatesAutoresizingMaskIntoConstraints = false
        NSLayoutConstraint.activate([
            contentView.topAnchor.constraint(equalTo: topAnchor),
            contentView.bottomAnchor.constraint(equalTo: bottomAnchor),
            contentView.leadingAnchor.constraint(equalTo: leadingAnchor),
            contentView.trailingAnchor.constraint(equalTo: trailingAnchor)
        ])
    }
    
    @IBAction func showPostReplies(_ sender: Any) {
        self.toggleReplies(show: true)
    }
    
    func getReplies() {
        apiClient.getReplies(postId: String(self.message.id), sort: "-created_at", perPage: 5, page: 1, completion: { replies in
            print(replies)
        })
    }
    
    func toggleReplies(show: Bool) {
        self.repliesOpen = show
        switch repliesOpen {
        case true:
            self.getReplies()
        case false:
            print("close")
        }
    }
}

So here I am, wondering how I can add replies to my post, then add replies to my replies. Maybe I'm taking this the wrong way, so a bit of help would be nice.

Mate, adding a table view to a table view cell is a really bad idea (so outrageous that I had to open the question).

In terms of UI, it's relatively straight-forward. You can make the post the section header or just a cell. Either way, all the replies will be also cells in the same table -- create a different UITableViewCell subclass for them & use indentation to achieve the hierarchy. (indentationLevel & indentationWidth properties of UITableviewCell) The actions of expand - collapse (getReplies) should be called not in the cell but in the viewController (or viewModel / presenter depending on what you are using) via delegates.

Your real concern should be coming up with a top-notch data structure for the table that will store posts + replies + reply expansion state + reply hierarchy level.

I hope this'll get you started on the right path. (Do not add table view inside a table view cell, you might actually achieve stack overflow if your replies go deep enough)

Here's a data structure I quickly came up with (doesn't include data fields but everything else you need to get it running.)

protocol Repliable {
    var replies: [Repliable] {get}
    var replyLevel: Int {get}
    var isPost: Bool {get}
}

struct Post: Repliable {
    //data fields
    
    let isPost = true
    let replyLevel = 0
    var replies: [Repliable]
}

struct Reply: Repliable {
    //data fields
    
    let isPost = false
    var replyLevel: Int
    var replies: [Repliable]
}

To use it, your tableview should use an array of Repliable. Each time you expand (fetch) replies you simply add them at the correct location in the array & add rows to the table. Your challenge now is just to keep them properly ordered in the array. Like so -> Post 1, Reply 1, Reply1 to Reply1, Reply 2, Post 2...

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM