在Swift中使用以编程方式创建的UITableViewCell子类

时间:2014-12-20 23:41:46

标签: ios uitableview swift

我正在使用以编程方式创建的自定义单元格的表格视图,不使用IB。我在谷歌周围环顾四周并询问过NSChat,但我仍然无法让它发挥作用。它只显示默认的表视图。提前谢谢!

EventCell.swift

import UIKit

class EventCell: UITableViewCell {

    var eventName: UILabel = UILabel()
    var eventCity: UILabel = UILabel()
    var eventTime: UILabel = UILabel()

    override init(style: UITableViewCellStyle, reuseIdentifier: String?) {
        super.init(style: style, reuseIdentifier: reuseIdentifier)

        self.contentView.addSubview(eventName)
        self.contentView.addSubview(eventCity)
        self.contentView.addSubview(eventTime)
    }

    required init(coder aDecoder: NSCoder) {
        super.init(coder: aDecoder)
    }

    override func layoutSubviews() {
        super.layoutSubviews()

        eventName = UILabel(frame: CGRectMake(20, 10, self.bounds.size.width - 40, 25))
        eventCity = UILabel(frame: CGRectMake(0, 0, 0, 0))
        eventTime = UILabel(frame: CGRectMake(0, 0, 0, 0))

    }

}

ViewController.swift

class ViewController: UITableViewController, UITableViewDelegate {

    var events: Dictionary<String, [String]> = ["0": ["Monroe Family", "La Cañada", "8:30"]]

    override func viewDidLoad() {
        super.viewDidLoad()
        tableView.dataSource = self;
        tableView.delegate = self;

        tableView.registerClass(EventCell.self, forCellReuseIdentifier: "EventCell")
    }

    override func didReceiveMemoryWarning() {
        super.didReceiveMemoryWarning()

    }

    override func tableView(tableView: UITableView, estimatedHeightForRowAtIndexPath indexPath: NSIndexPath) -> CGFloat {
        return UITableViewAutomaticDimension;
    }

    override func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        return events.count
    }

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

        var cellIdendifier: String = "EventCell"

        var cell: EventCell = tableView.dequeueReusableCellWithIdentifier(cellIdendifier, forIndexPath: indexPath) as EventCell
        cell = EventCell(style: .Default, reuseIdentifier: cellIdendifier)

        if let i = events[String(indexPath.row)] {
            cell.eventName.text = i[0]
            cell.eventCity.text = i[1]
            cell.eventTime.text = i[2]
        }

        cell.sizeToFit()

        return cell


    }
}

4 个答案:

答案 0 :(得分:27)

我有同样的问题。我在@drewag的答案中应用了这个建议,但还有一些其他问题。下面是一个简单的,概念验证示例,演示如何使用以编程方式创建的Right click on project - >BuildPath - >Configure BuildPath - >Libraries tab - > 子类。

下面的图片应该是它的外观。黄色矩形是自定义单元格中的UITableViewCell子视图。

enter image description here

代码

这是UITableViewCell子类。它的工作是初始化单元格及其内容,添加子视图,并布置子视图。

UILabel

这是视图控制器代码。

import UIKit
class MyCustomCell: UITableViewCell {

    var myLabel = UILabel()

    override init(style: UITableViewCellStyle, reuseIdentifier: String?) {
        super.init(style: style, reuseIdentifier: reuseIdentifier)

        myLabel.backgroundColor = UIColor.yellowColor()
        self.contentView.addSubview(myLabel)
    }

    required init?(coder aDecoder: NSCoder) {
        super.init(coder: aDecoder)
    }

    override func layoutSubviews() {
        super.layoutSubviews()

        myLabel.frame = CGRect(x: 20, y: 0, width: 70, height: 30)
    }
}

注意:

  • 我使用常规import UIKit class ViewController: UIViewController, UITableViewDelegate, UITableViewDataSource { @IBOutlet weak var tableView: UITableView! let myArray = ["one", "two", "three", "four"] let cellReuseIdendifier = "cell" override func viewDidLoad() { super.viewDidLoad() tableView.registerClass(MyCustomCell.self, forCellReuseIdentifier: cellReuseIdendifier) tableView.dataSource = self tableView.delegate = self } func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int { return myArray.count } func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell { let cell = tableView.dequeueReusableCellWithIdentifier(cellReuseIdendifier, forIndexPath: indexPath) as! MyCustomCell cell.myLabel.text = myArray[indexPath.row] return cell } } 而不是UIViewController。如果您使用UITableViewController,则删除UITableViewControllerUITableViewDelegate协议引用,因为这些对于UITableViewDataSource来说是多余的。您也不需要UITableViewController行。
  • 我在原始问题中找到的主要问题是@IBOutlet tableView。相反应该是eventName = UILabel(frame: CGRectMake(...))

答案 1 :(得分:26)

好的,首先要做一些重要的评论。

首先,每次表视图请求单元格而不是重用旧单元格时,您都会不必要地创建自己的新单元格。你应该删除这一行:

cell = EventCell(style: .Default, reuseIdentifier: cellIdendifier)

这是不必要的,因为dequeue会根据您为给定标识符注册的类自动创建新单元格。

第二,在布局代码时不应使用主屏幕边界。如果您的表视图不是整个宽度,这将分解。相反,您可以使用self.bounds,因此它始终与单元格本身相关。

第三次,您不应该调用setNeedsLayout或layoutIfNeeded,因为如果调用该方法,它已经在重新布局了所有内容。

第四,您应该在设置表视图数据源之前注册表视图单元类,以防万一UITableView在设置数据源时开始从数据源请求内容。

第五,您的两个子视图的大小为0,0因此无论如何它们都不会出现。

如果此代码确实在没有崩溃的情况下运行,那么您正在创建EventCells,因为您正在从dequeueReusableCellWithIdentifier:forIndexPath的结果进行强制转换。这意味着您只需要布局/显示/数据问题。

答案 2 :(得分:3)

您的特定代码无效,因为它在EventCell.layoutSubviews中创建新的UILabel。只有最初的UILabel被添加到视图树中,它们的大小可能是0&d; d。

我猜你想要更新他们的帧,例如更新EventCell类方法:

override func layoutSubviews() {
    super.layoutSubviews()

    eventName.frame = CGRectMake(20, 10, self.bounds.size.width - 40, 25)
    eventCity.frame = CGRectMake(<actual size>)
    eventTime.frame = CGRectMake(<actual size>)
}

答案 3 :(得分:3)

您可以在swift中使用延迟实例化,以避免不得不进入layoutSubviews / view生命周期舞蹈。

class EventCell: UITableViewCell {
  lazy public  var lblName = {
    return UILabel (frame: CGRectMake(10, 0, self.bounds.size.width , 40))
    }()

 lazy public  var lblCity = {
    return UILabel (frame: CGRectMake(10, 40, self.bounds.size.width , 20))
    }()
 lazy public  var lblTime = {
    return UILabel (frame: CGRectMake(self.bounds.size.width - 80, 10, , 25))
    }()


  override init(style: UITableViewCellStyle, reuseIdentifier: String?) {
    super.init(style: style, reuseIdentifier: reuseIdentifier)

    self.contentView.addSubview(lblName)
    self.contentView.addSubview(lblCity)
    self.contentView.addSubview(lblTime)
  }

}