How to embed a UITableView in a custom view

时间:2015-07-28 23:41:54

标签: ios swift uitableview custom-component

Goal

I want to create a custom view that has a UITableView as a subview.

enter image description here

The custom view creates the table view programmatically. To the outside world (i.e., the ViewController), though, the custom view itself would appear to be a table view.

What I've tried

lsb_release -c

After creating the UITableView programmatically and adding it as a subview to the custom view parent, I can't figure out how to get the custom view to act like it is the table view. That is, I don't know how to get the custom view to do the communication between the View Controller and the table view for the import UIKit class CustomTableView: UIView { // Do I make outlets? //@IBOutlet var dataSource: UITableViewDataSource? //@IBOutlet var delegate: UITableViewDelegate? required init(coder aDecoder: NSCoder) { super.init(coder: aDecoder) } override init(frame: CGRect){ super.init(frame: frame) } override func awakeFromNib() { super.awakeFromNib() } override func layoutSubviews() { super.layoutSubviews() var tableView: UITableView! tableView = UITableView(frame: self.bounds) // I'm not sure how to set the delegate and dataSource // tableView.dataSource = ??? // tableView.delegate = ??? self.addSubview(tableView) } } and delegate.

What I've read

These articles seemed good, but I got a little lost.

How do I make the custom view act like it's own table subview with regard to delegate and data source?

2 个答案:

答案 0 :(得分:2)

解决方案是使tableView成为自定义类的属性(建议使用@BaseZen)。然后在自定义类中提供属性和方法,以模仿和传递tableView所需的属性和方法。

import UIKit
@IBDesignable class UICustomTableView: UIView {

    private var myTableView: UITableView

    required init(coder aDecoder: NSCoder) {
        myTableView = UITableView()
        super.init(coder: aDecoder)
    }
    override init(frame: CGRect){
        myTableView = UITableView()
        super.init(frame: frame)
    }
    override func awakeFromNib() {
        super.awakeFromNib()
    }

    // TODO: @IBOutlet still can't be set in IB
    @IBOutlet weak var delegate: UITableViewDelegate? {
        get {
            return myTableView.delegate
        }
        set {
            myTableView.delegate = newValue
        }
    }

    // TODO: @IBOutlet still can't be set in IB
    @IBOutlet weak var dataSource: UITableViewDataSource? {
        get {
            return myTableView.dataSource
        }
        set {
            myTableView.dataSource = newValue
        }
    }

    func registerClass(cellClass: AnyClass?, forCellReuseIdentifier identifier: String) {
        myTableView.registerClass(cellClass, forCellReuseIdentifier: identifier)
    }

    func dequeueReusableCellWithIdentifier(identifier: String) -> UITableViewCell? {
        return myTableView.dequeueReusableCellWithIdentifier(identifier)
    }

    override func layoutSubviews() {
        super.layoutSubviews()

        // ...

        // setup UITableView
        myTableView.frame = self.bounds
        self.addSubview(myTableView)

        // ...
    }       
}

然后它可以像普通UITableView

一样使用
import UIKit
class TableViewDemoVC: UIViewController, UITableViewDelegate, UITableViewDataSource {

    @IBOutlet weak var customTableView: UICustomTableView!

    var items: [String] = ["One", "Two", "Three"]

    override func viewDidLoad() {
        super.viewDidLoad()

        // setup the table view from the IB reference
        customTableView.delegate = self
        customTableView.dataSource = self
        customTableView.registerClass(UITableViewCell.self, forCellReuseIdentifier: "cell")

    }

    func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {

        let cell: UITableViewCell = self.customTableView.dequeueReusableCellWithIdentifier("cell") as UITableViewCell!
        cell.textLabel?.text = self.items[indexPath.row]            
        return cell
    }

    // ...
}

答案 1 :(得分:1)

It's not the most elegant, but jump out a level:

java.lang.IOException: underlying stream returned 0 bytes

* IMPORTANT *

The key that you're missing is that class MyCustomViewController: UIViewController, UITableViewDelegate, UITableViewDataSource { override func viewDidLoad() { myCustomView = CustomTableView() myCustomView.frame = ... /* layout programatically */ /* Alternatively to the above 2 lines, lay out myCustomView in StoryBoard, and capture it as an @IBOutlet. It will then be ready here to muck with, well before it gets displayed and needs the data */ myCustomView.tableView.delegate = self myCustomView.tableView.dataSource = self } /* Now implement all your dataSource and delegate methods */ } must be a stored property of your custom view. It's important and needs to be promoted from a silly local! It should also be initialized in the awakeFromNib() function, even if you don't know the frame size. Then reset its frame at layout time.

At a higher level, I don't know "What You're Really Trying To Do." It may not actually be the right implementation technique to be embedding a UITableView within a custom view; consider just laying out the UITableView in the main view. Then if you need decoration around it, lay those out as separate views in StoryBoard.