如何从 ViewController 中的 xib (nib) 实例化 UIView / UITableView

Posted

技术标签:

【中文标题】如何从 ViewController 中的 xib (nib) 实例化 UIView / UITableView【英文标题】:How do I instantiate a UIView / UITableView from a xib (nib) in a ViewController 【发布时间】:2015-05-06 18:08:38 【问题描述】:

我想显示一个具有分段控件的用户界面,以及分段控件的每个部分的不同表格视图;因此,可以在 2 个表视图(好友和束)之间切换。 为了实现这一点,我做了以下工作

    在 Storyboard 中创建一个 ViewController 从 ViewController 中删除视图 使用关联的 xib 文件创建一个新的 UIViewController swift 类 将分段控件放在xib的主UIView中 在主 UIView 中放置一个内部 UIView 元素,以占据替换它的表格视图的空间 创建了UITableView的两个子类和对应的xib文件

我想到的一些选项:

我可以将 Interface Builder 中的内部 UIView 的类设置为其中一个表视图的类,但我不知道如何实例化另一个来代替初始视图。如果我创建了重叠的内部 UIView,每个 UIView 都与一个表格视图相关联,并在我切换分段控件时隐藏其中一个,这实际上是可行的,但视图的重叠特性使布局变得困难且不直观。 我想知道怎么做:实例化表格视图来代替单个主 UIView 元素 替代方案:拥有一个 UITableView 子类,该子类具有基于分段控件状态的条件,用于显示哪些数据。我不太喜欢这个,因为它会将表格视图的代码混合在一起。在这种情况下,我什至不再需要使用 xibs,我可以在情节提要中使用一个表格视图来执行此操作。

** 视图控制器代码 **

@objc(BuddiesBunchesViewController) class BuddiesBunchesViewController: UIViewController 

    @IBOutlet weak var segmentedControl: UISegmentedControl!

    @IBOutlet weak var tableView: UIView!

    override func viewDidLoad() 
        super.viewDidLoad()

        // Do any additional setup after loading the view.

        // Instantiate tableView here to BuddiesTableView
    

    override func didReceiveMemoryWarning() 
        super.didReceiveMemoryWarning()
    

    @IBAction func segmentedControlIndexChanged(sender: AnyObject) 
        switch segmentedControl.selectedSegmentIndex 
        case 0: // Buddies
            // Set tableview to the buddies table view
        case 1: // Bunches
            // Set tableview to the buddies table view
        default:
            break;
        
    

** 表格视图 **

@IBDesignable class BuddiesTableView: UITableView, UITableViewDataSource, UITableViewDelegate 

    var view: UIView!

    var nibName: String = "BuddiesTableView"

    //init

    override init(frame: CGRect) 
        // set properties

        super.init(frame: frame)

        // Set anything that uses the view or visible bounds
        setup()
    

    required init(coder aDecoder: NSCoder) 
        //set properties

        super.init(coder: aDecoder)

        // Setup
        setup()
    

    func setup() 
        view = loadViewFromNib()

        view.frame = self.bounds
        view.autoresizingMask = UIViewAutoresizing.FlexibleWidth | UIViewAutoresizing.FlexibleHeight

         addSubview(view)
    

    func loadViewFromNib() -> UIView 
        let bundle = NSBundle(forClass: self.dynamicType)
        let nib = UINib(nibName: nibName, bundle: bundle)
        let view = nib.instantiateWithOwner(self, options: nil)[0] as! UIView

        return view
    

// MARK: - Table View

    func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int 
         return 10
    

    func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell 
        let cell: UITableViewCell = UITableViewCell(style: UITableViewCellStyle.Subtitle, reuseIdentifier: "MyTestCell")
        cell.textLabel?.text = "\(indexPath.row)"
        return cell
    

【问题讨论】:

【参考方案1】:

我个人不会创建两个表视图并将它们交换出来。两者之间唯一的显着区别是它们是不同的实例,您可以在数据源代码中进行测试。他们会指向不同的数据源吗?为什么不即时更改数据源,而不是表视图?

创建一个表格视图。创建两个(或更多)类作为数据源(可能还有委托)。如果它们有任何共同的行为,它们可以基于一个共同的超类。

当分段控件值发生变化时,只需将表格视图的 dataSource 属性更改为指向具有该状态代码的类。如果更改数据源不会自动重新加载它,您可能还需要调用 -reloadData。

@IBOutlet private weak var tableView: UITableView!
let moviesDataSource = MyMoviesDataSource()
let tvShowsDataSource = MyTVShowsDataSource()

@IBAction func segmentedControlTouched(sender: UISegmentedControl) 
    switch sender.selectedSegmentIndex 
    case 0:
        self.tableView.dataSource = self.moviesDataSource
        self.tableView.delegate = self.moviesDataSource
    case 1:
        self.tableView.dataSource = self.tvShowsDataSource
        self.tableView.delegate = self.tvShowsDataSource
    
    self.tableView.reloadData()

【讨论】:

糟糕。 @Amit89 打败了我。 好的,我从没想过移出 tableview 数据源并委托给单独的类。那么在段控制更改时,我将如何交换这些类?你能提供一点代码吗?【参考方案2】:

我的解决方案如下。

您有一个具有两个段的段控件,因此您可以只拥有一个UITableView 对象并根据段控件selectedSegmentIndex 编号更改数据源,然后重新加载表视图,而不是拥有两个表视图。在情节提要中,将表格视图放在UIVIewController 的顶部并为此创建一个@IBOutlet

【讨论】:

如果两个表格视图需要不同类型的自定义单元格怎么办?其中一个表格视图需要标题,而另一个不需要,所以我认为这个解决方案不能解决这些情况,不是吗? 在 UIViewController 之上的表格视图中,创建两个不同的原型单元格,并为每个单元格创建两个 UITableViewCell 子类,并根据段控件使用所需的单元格。对于标题,对于标题和自定义标题视图,我们有委托方法,在那里检查您需要标题详细信息的哪个段,对于另一个返回空字符串“”作为标题,为标题视图返回 nil。

以上是关于如何从 ViewController 中的 xib (nib) 实例化 UIView / UITableView的主要内容,如果未能解决你的问题,请参考以下文章

从 XIB Viewcontroller 中的 segmentcontrol 到 Storyboard Viewcontroller

如何通过推送从 xib 转换到 ViewController

从 xib 文件中的操作按钮推送另一个 Viewcontroller

如何从 UIView 类的 xib 文件导航到 ViewController

iOS - 使用 xib 中的 tabBarController 将数据从一个 viewController 传递到另一个 viewController

仅使用一个 ViewController 从 XIB 切换