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

Ios 在Swift中使用以编程方式创建的UITableViewCell子类,ios,uitableview,swift,Ios,Uitableview,Swift,我正在处理一个带有自定义单元格的表视图,该单元格是通过编程方式创建的,没有使用IB。我在Google上四处查看,在NSChat中四处询问,但我仍然无法让它工作。它只显示默认的表视图。提前谢谢 EventCell.swift import UIKit class EventCell: UITableViewCell { var eventName: UILabel = UILabel() var eventCity: UILabel = UILabel() var ev

我正在处理一个带有自定义单元格的表视图,该单元格是通过编程方式创建的,没有使用IB。我在Google上四处查看,在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


    }
}
类ViewController:UITableViewController、UITableViewDelegate{
var事件:Dictionary=[“0”:[“门罗家族”、“拉卡尼亚达”、“8:30”]]
重写func viewDidLoad(){
super.viewDidLoad()
tableView.dataSource=self;
tableView.delegate=self;
注册表类(EventCell.self,forCellReuseIdentifier:“EventCell”)
}
重写函数didReceiveMemoryWarning(){
超级。我收到了记忆警告()
}
重写func tableView(tableView:UITableView,EstimatedHeightForrowatineXpath indexPath:NSIndexPath)->CGFloat{
返回UITableViewAutomaticDimension;
}
重写func tableView(tableView:UITableView,numberofrowsinssection:Int)->Int{
return events.count
}
重写func tableView(tableView:UITableView,cellForRowAtIndexPath:nsindepath)->UITableView单元格{
var-cellIdendifier:String=“EventCell”
var cell:EventCell=tableView.dequeueReusableCellWithIdentifier(CellIdIndifier,forIndexPath:indexPath)作为EventCell
cell=EventCell(样式:。默认,reuseIdentifier:cellIdentifier)
如果let i=events[String(indexPath.row)]{
cell.eventName.text=i[0]
cell.eventCity.text=i[1]
cell.eventTime.text=i[2]
}
cell.sizeToFit()
返回单元
}
}

好的,首先是一些重要的评论

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

cell = EventCell(style: .Default, reuseIdentifier: cellIdendifier)
这是不必要的,因为出列将根据您为给定标识符注册的类根据需要自动创建新单元

其次,在布局代码时不应使用主屏幕边界。如果您的表视图不是全宽,则会发生故障。相反,您可以使用
self.bounds
,使其始终相对于单元格本身

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

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

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


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

您的特定代码无法工作,因为它正在EventCell.LayoutSubView中创建新的UILabel。只有初始UILabel被添加到视图树中,它们的大小可能为0'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>)
}
覆盖函数布局子视图(){
super.layoutSubviews()
eventName.frame=CGRectMake(20,10,self.bounds.size.width-40,25)
eventCity.frame=CGRectMake()
eventTime.frame=CGRectMake()
}

您可以在swift中使用惰性实例化,以避免陷入布局子视图/视图生命周期舞蹈

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

} 

我也有同样的问题。我在@drewag的回答中应用了这个建议,但还有一些额外的问题。下面是一个简单的概念验证示例,演示如何使用编程创建的
UITableViewCell
子类

下图是它应该是什么样子。黄色矩形是自定义单元格中的
UILabel
子视图

代码 下面是UITableViewCell子类。它的工作是初始化单元格及其内容、添加子视图和布局子视图

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
    。如果使用
    UITableViewController
    ,请删除
    UITableViewDelegate
    UITableViewDataSource
    协议引用,因为它们对于
    UITableViewController
    是多余的。您也不需要
    @IBOutlet tableView
  • 我在原始问题中发现的主要问题是
    eventName=UILabel(frame:CGRectMake(…)
    。相反,它应该是
    eventName.frame=CGRect(…)

让CellIdIndifier:String=“EventCell”,因为cellIdentifier未发生突变。让cell:EventCell=tableView。将可重用CellWithIdentifier(CellIdIndifier,forIndexPath:indexPath)作为一个标识符(CellIdIndeXPath)退出队列!EventCell,因为cell未发生突变并使用强制向下投射!在这种情况下,self.bounds是否与self.contentView.bounds相同?您好!我有一个问题,如果我有一个自定义init,有我自己的参数,你会如何处理这个问题?那是不是不可能把牢房排出来?我必须始终创建它们?@PMT您的自定义init应该接受重用标识符,然后将其传递给指定的
init(style:reuseIdentifier:)
。然后你可以像平常一样将它出列。@drewag但是出列函数不会使用我的自定义函数,如果我手动初始化它,那么出列就不会做任何事情,因为我总是初始化它,对吗?有没有办法知道出列是在创建一个新单元(然后我可以使用我自己的init)还是在重用一个单元(然后我让它去做,我不做init)?。我