使用 Swift 编写自定义 UITableViewCell (编程方式)(文档)?

28

我一直在努力寻找关于如何在Swift中创建高级TableView的文档/教程/示例,但除了无尽的Storyboard教程外,我找不到什么。

我正在使用没有storyboards和nibs的方式进行开发。除了 Apple 官方 /不太好/解释的库之外,我找不到任何其他文档。

与其试图解释我所寻找的内容,我更愿意直接展示下面设计的图片。

enter image description here

现在,我显然并不是要求你们为我创建这个,我只是希望您能向我提供一个链接,来解释如何使单元格不同?以及如何在单元格内编程定位元素。

我一直在寻找单元格约束,但我找不到任何文档?

我也研究了原型单元格,但我找到的都与Storyboard相关。

我希望你们能向我展示一些类似的示例,或者提供一些相关的文档/教程。

另一个重要的事情是,任何我找到的不使用storyboards的文档都使用tableViewController。

我使用的是UIViewController和UITableView,而不是tableViewController,这似乎对它的工作方式有很大影响。

现在我只是想让一个原型工作。

以下是我的数据:

var objects = NSMutableArray()
var dataArray = [   ["stockName":"CTC Media Inc.","action":"sell","stockPrice":12.44],
                    ["stockName":"Transglobal Energy","action":"buy","stockPrice":39.40],
                    ["stockName":"NU Skin Enterprises","action":"buy","stockPrice":4.18]
                ]

尽管如此,我只能获取并显示其中的一条数据。

    func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
    //return self.stocks.count
    return dataArray.count
}

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

    let cell = tableView.dequeueReusableCellWithIdentifier("cell", forIndexPath: indexPath) as UITableViewCell
    let object = dataArray[indexPath.row] as NSDictionary
    cell.textLabel?.text = object["stockName"] as? String

    return cell

}

func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
    println("You selected cell #\(indexPath.row)!")
}

但我仍然不知道如何定位这些数据,或者如何添加更多内容。例如右侧带有特定背景颜色的UIView。在该UIView内部使UILabel居中,添加具有填充、自定义单元格间距的左侧UIView等等。

任何帮助、文档链接或建议都将不胜感激!

编辑:

我尝试在单元格内部添加约束条件。"cell.view.addConstraints("

但当然它会抛出一个错误,说"UITableViewCell没有名为view的成员"。

因此,关于如何在单元格内添加约束条件,我仍然一头雾水 :(

编辑2 - 进展:

使用以下代码,我设法让UIView显示出来:

        testView.setTranslatesAutoresizingMaskIntoConstraints(false)
    testView.backgroundColor = UIColor.redColor()
    cell.addSubview(testView)

    var viewsDictionary = [ "testView":testView]
    cell.addConstraints(
        NSLayoutConstraint.constraintsWithVisualFormat(
            "H:|-50-[testView]|", options: nil, metrics: nil, views: viewsDictionary))
    cell.addConstraints(
        NSLayoutConstraint.constraintsWithVisualFormat(
            "V:|[testView]|", options: nil, metrics: nil, views: viewsDictionary))

然而,由于某些原因,它只出现在最后一个单元格,而不是所有单元格中?


1
谢谢你的评论!我已经创建了我需要的所有对象,但是我没有办法把它们放在这些单元格里。我知道约束是如何工作的。但是我不知道如何向单元格内的物品添加约束?是tableView为我创建一个cell对象吗?是什么决定了单元格标签的位置?我该如何将这些对象添加到我的单元格中。 - MLyck
1
你好Huy Nghia,感谢您的评论!是的,我看到了那个教程,但像我找到的其他教程一样,它基于storyboards,单元格的设计是在storyboard中使用原型单元格完成的,而不是以编程方式完成的 :( - MLyck
以编程方式?基本上是在代码中创建视图而不是在Storyboard中拖放?那么...你的问题是什么? - Huy Nghia
你的问题是你只使用了dequeueReusableCellWithIdentifier,但从未创建cell,那么tableView如何为你重用cell呢? - Huy Nghia
1
在阅读这个问题的时候,我微笑了,我感觉你兄弟!因为我正在学习Swift并进入那个头痛的阶段,对于这个Storyboard Jumbo Mumbo,可怜的文档,这些白痴教程中缺乏理解,好像所有的观众都不知道什么是类和对象!还有所有这些限制和苹果的“标准”设计...创造力到哪里去了!!还有这些荒谬可笑的长方法名...真的苹果!!! 我感谢上帝我来自Windows/Linux/Web背景,那里编程是认真的! - Engineeroholic
显示剩余8条评论
1个回答

65

enter image description here

我只是玩了一下。虽然所有的颜色/字体都不太对,但这将为您提供一个很好的起点。希望能对您有所帮助。

class Stock {
var name: String?
var action: String?
var price: String?
init(stockData: [String: AnyObject]) {
    if let n = stockData["stockName"] as? String {
        name = n
    }
    if let a = stockData["action"] as? String {
        action = a
    }
    if let p = stockData["stockPrice"] as? Float {
        price = NSString(format: "%.2f", p)
    }
}

var backgroundColor: UIColor {
    if action == "sell" {
        return UIColor.greenColor()
    }
    return UIColor.blueColor()
}

var typeColor: UIColor {
    if action == "sell" {
        return UIColor.blackColor()
    }
    return UIColor.purpleColor()
}

var priceLabelColor: UIColor {
    if action == "sell" {
        return UIColor.redColor()
    }
    return UIColor.greenColor()
}
}


class StockCell: UITableViewCell {

let padding: CGFloat = 5
var background: UIView!
var typeLabel: UILabel!
var nameLabel: UILabel!
var priceLabel: UILabel!

var stock: Stock? {
    didSet {
        if let s = stock {
            background.backgroundColor = s.backgroundColor
            priceLabel.text = s.price
            priceLabel.backgroundColor = s.priceLabelColor
            typeLabel.text = s.action
            typeLabel.backgroundColor = s.typeColor
            nameLabel.text = s.name
            setNeedsLayout()
        }
    }
}

override init(style: UITableViewCellStyle, reuseIdentifier: String?) {
    super.init(style: style, reuseIdentifier: reuseIdentifier)
    backgroundColor = UIColor.clearColor()
    selectionStyle = .None

    background = UIView(frame: CGRectZero)
    background.alpha = 0.6
    contentView.addSubview(background)

    nameLabel = UILabel(frame: CGRectZero)
    nameLabel.textAlignment = .Left
    nameLabel.textColor = UIColor.blackColor()
    contentView.addSubview(nameLabel)

    typeLabel = UILabel(frame: CGRectZero)
    typeLabel.textAlignment = .Center
    typeLabel.textColor = UIColor.whiteColor()
    contentView.addSubview(typeLabel)

    priceLabel = UILabel(frame: CGRectZero)
    priceLabel.textAlignment = .Center
    priceLabel.textColor = UIColor.whiteColor()
    contentView.addSubview(priceLabel)
}

required init(coder aDecoder: NSCoder) {
    fatalError("init(coder:) has not been implemented")
}

override func prepareForReuse() {
    super.prepareForReuse()

}

override func layoutSubviews() {
    super.layoutSubviews()
    background.frame = CGRectMake(0, padding, frame.width, frame.height - 2 * padding)
    typeLabel.frame = CGRectMake(padding, (frame.height - 25)/2, 40, 25)
    priceLabel.frame = CGRectMake(frame.width - 100, padding, 100, frame.height - 2 * padding)
    nameLabel.frame = CGRectMake(CGRectGetMaxX(typeLabel.frame) + 10, 0, frame.width - priceLabel.frame.width - (CGRectGetMaxX(typeLabel.frame) + 10), frame.height)
}
}

在你的视图控制器中

var stocks: [Stock] = []

override func viewDidLoad() {
    super.viewDidLoad()

    view.backgroundColor = UIColor.whiteColor()

    for stockData in dataArray {
        var stock = Stock(stockData: stockData)
        stocks.append(stock)
    }


    tableView = UITableView(frame: view.bounds, style: .Grouped)
    tableView.delegate = self
    tableView.dataSource = self
    tableView.separatorStyle = .None
    tableView.registerClass(StockCell.self, forCellReuseIdentifier: NSStringFromClass(StockCell))
    view.addSubview(tableView)
}



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

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

    let cell = tableView.dequeueReusableCellWithIdentifier( NSStringFromClass(StockCell), forIndexPath: indexPath) as StockCell
    cell.stock = stocks[indexPath.row]
    return cell

}

func tableView(tableView: UITableView, heightForRowAtIndexPath indexPath: NSIndexPath) -> CGFloat {
    return 70
}

自定义单元格

class StockCell: UITableViewCell {

let padding: CGFloat = 5
var background: UIView!
var typeLabel: UILabel!
var nameLabel: UILabel!
var priceLabel: UILabel!

var stock: Stock? {
    didSet {
        if let s = stock {
            background.backgroundColor = s.backgroundColor
            priceLabel.text = s.price
            priceLabel.backgroundColor = s.priceLabelColor
            typeLabel.text = s.action
            typeLabel.backgroundColor = s.typeColor
            nameLabel.text = s.name
            setNeedsLayout()
        }
    }
}

override init(style: UITableViewCellStyle, reuseIdentifier: String?) {
    super.init(style: style, reuseIdentifier: reuseIdentifier)
    backgroundColor = UIColor.clearColor()
    selectionStyle = .None

    background = UIView(frame: CGRectZero)
    background.alpha = 0.6
    contentView.addSubview(background)

    nameLabel = UILabel(frame: CGRectZero)
    nameLabel.textAlignment = .Left
    nameLabel.textColor = UIColor.blackColor()
    contentView.addSubview(nameLabel)

    typeLabel = UILabel(frame: CGRectZero)
    typeLabel.textAlignment = .Center
    typeLabel.textColor = UIColor.whiteColor()
    contentView.addSubview(typeLabel)

    priceLabel = UILabel(frame: CGRectZero)
    priceLabel.textAlignment = .Center
    priceLabel.textColor = UIColor.whiteColor()
    contentView.addSubview(priceLabel)
}

required init(coder aDecoder: NSCoder) {
    fatalError("init(coder:) has not been implemented")
}

override func prepareForReuse() {
    super.prepareForReuse()

}

override func layoutSubviews() {
    super.layoutSubviews()
    background.frame = CGRectMake(0, padding, frame.width, frame.height - 2 * padding)
    typeLabel.frame = CGRectMake(padding, (frame.height - 25)/2, 40, 25)
    priceLabel.frame = CGRectMake(frame.width - 100, padding, 100, frame.height - 2 * padding)
    nameLabel.frame = CGRectMake(CGRectGetMaxX(typeLabel.frame) + 10, 0, frame.width - priceLabel.frame.width - (CGRectGetMaxX(typeLabel.frame) + 10), frame.height)
}
}

哇,我只是在寻找一点文档提示,或者想让有人告诉我可以为单元格创建一个类。但是,非常完美的答案,非常感谢!我按照下面回答中的文档所述做了一些不同的东西。但这绝对是更好的答案。 - MLyck
1
@user100002 很高兴能帮到你。我有点匆忙,所以忘记了在重用单元格时重置所有单元格子视图。你只需要在 prepareForReuse 中将所有标签的文本设置为 nil,并将背景颜色设置为默认颜色(如果有的话)。 - HMHero
@HMHero - 非常感谢你。这是一个完美而简单的设计模式分解,非常直接和简单。感谢你的时间! - Dolbex

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接