【问题标题】:How to embed a UITableView in a custom view如何在自定义视图中嵌入 UITableView
【发布时间】:2015-10-19 18:06:32
【问题描述】:

目标

我想创建一个以 UITableView 作为子视图的自定义视图。

自定义视图以编程方式创建表视图。但是,对于外部世界(即 ViewController),自定义视图本身似乎是一个表格视图。

我尝试过的

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)
       
    }
}

以编程方式创建 UITableView 并将其作为子视图添加到自定义视图父级后,我无法弄清楚如何让自定义视图像表格视图一样工作。也就是说,我不知道如何让自定义视图为delegatedataSource 做View Controller 和table view 之间的通信。

我读到的

这些文章看起来不错,但我有点失落。

如何使自定义视图在委托和数据源方面表现得像它自己的表子视图?

【问题讨论】:

  • 通常情况下,UIView“看起来”是视图控制器的表视图的唯一方式是它实际上是 UITableView 的子类。这是你的意思吗?
  • @algal,在这种情况下,我并不是要继承 UITableView。我正在尝试为垂直蒙古语制作水平 TableView。当我为垂直蒙古文 TextView 执行此操作时,我可以让自动布局工作的唯一方法是将其包装在两个容器视图中。请参阅this answer 及其问题。

标签: ios swift uitableview custom-component


【解决方案1】:

不是最优雅,而是跳出一个关卡:

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 */
}

* 重要 *

您缺少的关键是tableView 必须是您的自定义视图的存储属性。这很重要,需要从一个愚蠢的当地人那里得到提升!它也应该在 awakeFromNib() 函数中初始化,即使您不知道帧大小。然后在布局时重置它的框架。

在更高的层次上,我不知道“你真正想要做什么”。在自定义视图中嵌入 UITableView 实际上可能不是正确的实现技术;考虑在主视图中布置 UITableView。然后,如果您需要围绕它进行装饰,请将它们作为单独的视图布置在 StoryBoard 中。

【讨论】:

  • 谢谢。我将尝试将tableView 设为属性。理想情况下,我想去掉myCustomView.tableView.delegate 的中间层,然后做myCustomView.delegate。我真正想做的是制作一个水平滚动的表格视图,用于传统的蒙古语。请参阅thisthis 问题。我试图让它表现得像一个普通的 UITableView。
  • 在这种情况下,子类 UITableView 并将您的自定义代码放在那里,而不是用一个不添加任何内容的琐碎层包装它。请务必在 StoryBoard 的 Identity Inspector 中将类设置更新为您的自定义子类。我可能会问为什么要挂断TableView?将其旋转 90 度很容易,但会导致顶部或底部出现标注指示器等奇怪现象,感觉不对劲。相反,为什么不使用UICollectionView?前期工作较多,但您只需使用流式布局并获得很大的布局灵活性。
  • 我会调查UICollectionView。我不能只旋转(和翻转)子类TableView 的原因是自动布局不再适用于已转换的视图。 Using two container views 是一种解决方法,尽管不太理想。
【解决方案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
    }

    // ...
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-10-22
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-03-04
    相关资源
    最近更新 更多