decipher
decipher

Reputation: 148

How can I add a UITableView as a subview to a UIView?

First, this is possible and is this a good idea?

I don't want the UITableView to fill up the whole controller and I want to control the location of this view as I am learning. I have tried searching for tutorials showing this, but I am coming up empty handed as I have tried to implement this functionality.

So, I have a ChildView that subclasses UIView. This view implements or conforms to the necessary UITableView protocols such that I can set the delegate and dataSource to the ChildView. However, I can't seem to make it work properly. Can someone perhaps help me answering why? This is my first time working with UITableViews, so I don't have much experience yet. Working on it! :)

class ChildView: UIView
{
    let childTableView = UITableView()

    override init(frame: CGRect)
    {
        super.init(frame: frame)

        childTableView.register(ChildTableViewCell.self, forCellReuseIdentifier: "cellId")

        childTableView.delegate = self
        childTableView.dataSource = self

        childTableView.translatesAutoresizingMaskIntoConstraints = false
        addSubview(childTableView)

        childTableView.topAnchor.constraint(equalTo: self.topAnchor, constant: 0).isActive = true
        childTableView.leftAnchor.constraint(equalTo: self.leftAnchor, constant: 0).isActive = true
        childTableView.rightAnchor.constraint(equalTo: self.rightAnchor, constant: 0).isActive = true
        childTableView.bottomAnchor.constraint(equalTo: self.bottomAnchor, constant: 0).isActive = true

        setupLayout()
    }

    private func setupLayout()
    {
        self.layer.cornerRadius = 13
        self.backgroundColor = UIColor.white
        self.layer.borderWidth = 2
        self.layer.borderColor = UIColor.black.cgColor
    }

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

extension ChildView: UITableViewDataSource, UITableViewDelegate
{
    func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int
    {
        return 10
    }

    func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell
    {
        return tableView.dequeueReusableCell(withIdentifier: "cellId", for: indexPath)
    }
}


class ChildTableViewCell: UITableViewCell
{
    override init(style: UITableViewCellStyle, reuseIdentifier: String?)
    {
        super.init(style: style, reuseIdentifier: reuseIdentifier)
        setupViews()
    }

    private func setupViews()
    {
        // Nothing yet. 
    }

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

Edit 1: Included an image of the view that I am trying to fill with a UITableView.

Edit 2: I have added the code that makes it work in the ChildView class.

Upvotes: 1

Views: 2907

Answers (2)

Andreas Oetjen
Andreas Oetjen

Reputation: 10199

From an architectural point of view, you shouldn't do this. A view should only display data that it get's from somewhere outside. It should not act as a data source and try to get it's own data. If somebody reads your code (imaging yourself in one year), no-one would expect a view to behave in the way you implemented it.

Then, you do not display the table view anywhere. You'll have to add it as a subview to self and setup its frame / autolayout constraints to react on resizing etc.

If you want to separate the data source code from the view controller, you should create your own class which implements UITableViewDataSource, instantiate it, set it as the data source to the table view, and there you go. Separating the delegate would work the same, but maybe it is better to keep it in the view controller, because this acts as a co-ordinator between all the views in it.

Upvotes: 4

iOS Geek
iOS Geek

Reputation: 4855

Here is Sample code Posted , You can check this out Adding two tableViews in Different Views as Subview , used parent view is a ContainerView but you cause same code and just add subview in Your Normal UIView

Reference Code :

/// Class Obj
    private lazy var FirstObject: firstVC =
      {
        // Instantiate View Controller
        let viewController = self.storyboard?.instantiateViewController(withIdentifier: "firstVC") as! firstVC

        // Add View Controller as Child View Controller
        self.addChildViewController(viewController)
        return viewController
      }()


/// Adding it as Subview:
 private func add(asChildViewController viewController: UIViewController)
{
    // Configure Child View
    viewController.view.frame = CGRect(x: 0, y: 0, width: self.firstContainer.frame.size.width, height: self.firstContainer.frame.size.height)

    // Add Child View Controller
    addChildViewController(viewController)
    viewController.view.translatesAutoresizingMaskIntoConstraints = true

    // Add Child View as Subview
    firstContainer.addSubview(viewController.view)

    // Notify Child View Controller
    viewController.didMove(toParentViewController: self)
}

GitHub Repo - https://github.com/RockinGarg/Container_Views.git

enter image description here

Upvotes: 0

Related Questions