使用 Swift 以编程方式自定义 UITableViewCell
Posted
技术标签:
【中文标题】使用 Swift 以编程方式自定义 UITableViewCell【英文标题】:Custom UITableViewCell programmatically using Swift 【发布时间】:2014-10-14 07:32:07 【问题描述】:大家好,我正在尝试创建自定义 UITableViewCell
,但我在模拟器上什么也看不到。你能帮帮我吗?
只有var labUserName = UILabel(frame: CGRectMake(0.0, 0.0, 130, 30));
才能看到标签
但它与单元格重叠。没看懂,Auto Layout 应该知道每个单元格的首选尺寸/最小尺寸吧?
谢谢
import Foundation
import UIKit
class TableCellMessages: UITableViewCell
var imgUser = UIImageView();
var labUserName = UILabel();
var labMessage = UILabel();
var labTime = UILabel();
override init(style: UITableViewCellStyle, reuseIdentifier: String)
super.init(style: style, reuseIdentifier: reuseIdentifier)
imgUser.layer.cornerRadius = imgUser.frame.size.width / 2;
imgUser.clipsToBounds = true;
contentView.addSubview(imgUser)
contentView.addSubview(labUserName)
contentView.addSubview(labMessage)
contentView.addSubview(labTime)
//Set layout
var viewsDict = Dictionary <String, UIView>()
viewsDict["image"] = imgUser;
viewsDict["username"] = labUserName;
viewsDict["message"] = labMessage;
viewsDict["time"] = labTime;
//Image
//contentView.addConstraints(NSLayoutConstraint.constraintsWithVisualFormat("H:|-[image(100)]-'", options: nil, metrics: nil, views: viewsDict));
//contentView.addConstraints(NSLayoutConstraint.constraintsWithVisualFormat("V:|-[image(100)]-|", options: nil, metrics: nil, views: viewsDict));
contentView.addConstraints(NSLayoutConstraint.constraintsWithVisualFormat("V:|-[username]-[message]-|", options: nil, metrics: nil, views: viewsDict));
contentView.addConstraints(NSLayoutConstraint.constraintsWithVisualFormat("H:|-[username]-|", options: nil, metrics: nil, views: viewsDict));
contentView.addConstraints(NSLayoutConstraint.constraintsWithVisualFormat("H:|-[message]-|", options: nil, metrics: nil, views: viewsDict));
required init(coder aDecoder: NSCoder)
fatalError("init(coder:) has not been implemented")
【问题讨论】:
如果您在单元格中看到重叠的图像,则可能是单元格高度设置不正确。见:***.com/questions/494562/… 我只在使用 CGRectMake 时看到重叠,但我不想使用 CGRectMake,我想自动使用, 我想要自动布局来控制大小,这是我不明白的一件事。 请帮忙,里面的标签应该有自己的尺寸,不用我告诉他们尺寸是多少? 我知道这个线程很旧,对我来说,当标签、视图等所有 UI 元素上的“translatesAutoresizingMaskIntoConstraints = false”时,约束效果更好 【参考方案1】:让我们做一些假设:
您有一个带有Storyboard
的ios8 项目,其中包含一个UITableViewController
。它的tableView
有一个独特的原型UITableViewCell
,具有自定义样式和标识符:“cell”。
UITableViewController
将链接到 TableViewController
类,cell
将链接到 CustomTableViewCell
类。
然后您将能够设置以下代码(针对 Swift 2 更新):
CustomTableViewCell.swift:
import UIKit
class CustomTableViewCell: UITableViewCell
let imgUser = UIImageView()
let labUserName = UILabel()
let labMessage = UILabel()
let labTime = UILabel()
override func awakeFromNib()
super.awakeFromNib()
imgUser.backgroundColor = UIColor.blueColor()
imgUser.translatesAutoresizingMaskIntoConstraints = false
labUserName.translatesAutoresizingMaskIntoConstraints = false
labMessage.translatesAutoresizingMaskIntoConstraints = false
labTime.translatesAutoresizingMaskIntoConstraints = false
contentView.addSubview(imgUser)
contentView.addSubview(labUserName)
contentView.addSubview(labMessage)
contentView.addSubview(labTime)
let viewsDict = [
"image": imgUser,
"username": labUserName,
"message": labMessage,
"labTime": labTime,
]
contentView.addConstraints(NSLayoutConstraint.constraintsWithVisualFormat("V:|-[image(10)]", options: [], metrics: nil, views: viewsDict))
contentView.addConstraints(NSLayoutConstraint.constraintsWithVisualFormat("V:[labTime]-|", options: [], metrics: nil, views: viewsDict))
contentView.addConstraints(NSLayoutConstraint.constraintsWithVisualFormat("V:|-[username]-[message]-|", options: [], metrics: nil, views: viewsDict))
contentView.addConstraints(NSLayoutConstraint.constraintsWithVisualFormat("H:|-[username]-[image(10)]-|", options: [], metrics: nil, views: viewsDict))
contentView.addConstraints(NSLayoutConstraint.constraintsWithVisualFormat("H:|-[message]-[labTime]-|", options: [], metrics: nil, views: viewsDict))
TableViewController.swift:
import UIKit
class TableViewController: UITableViewController
override func viewDidLoad()
super.viewDidLoad()
//Auto-set the UITableViewCells height (requires iOS8+)
tableView.rowHeight = UITableViewAutomaticDimension
tableView.estimatedRowHeight = 44
override func numberOfSectionsInTableView(tableView: UITableView) -> Int
return 1
override func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int
return 100
override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell
let cell = tableView.dequeueReusableCellWithIdentifier("cell", forIndexPath: indexPath) as! CustomTableViewCell
cell.labUserName.text = "Name"
cell.labMessage.text = "Message \(indexPath.row)"
cell.labTime.text = NSDateFormatter.localizedStringFromDate(NSDate(), dateStyle: .ShortStyle, timeStyle: .ShortStyle)
return cell
您会期待这样的显示(iPhone 横向):
【讨论】:
在你给它像 cell.labUerName.text = "Name" 之类的参数之前,这似乎是在执行 awakefromnib 此代码首先调用 awakefromnib,而不是将变量传递给单元类。正因为如此,我遇到了崩溃,应该怎么办? 要移除对 Interface Builder 注册 forCellReuseIdentifier 的依赖,将以下行添加到 loadView() 中的 UITableViewController i> 或 ViewDidLoad():tableView.register(CustomTableViewCell.classForCoder(), forCellReuseIdentifier: "cell")
.【参考方案2】:
这是答案 Imanou Petit 的 swift 3 的更新。
CustomTableViewCell.swift:
import Foundation
import UIKit
class CustomTableViewCell: UITableViewCell
let imgUser = UIImageView()
let labUerName = UILabel()
let labMessage = UILabel()
let labTime = UILabel()
override init(style: UITableViewCellStyle, reuseIdentifier: String?)
super.init(style: style, reuseIdentifier: reuseIdentifier)
imgUser.backgroundColor = UIColor.blue
imgUser.translatesAutoresizingMaskIntoConstraints = false
labUerName.translatesAutoresizingMaskIntoConstraints = false
labMessage.translatesAutoresizingMaskIntoConstraints = false
labTime.translatesAutoresizingMaskIntoConstraints = false
contentView.addSubview(imgUser)
contentView.addSubview(labUerName)
contentView.addSubview(labMessage)
contentView.addSubview(labTime)
let viewsDict = [
"image" : imgUser,
"username" : labUerName,
"message" : labMessage,
"labTime" : labTime,
] as [String : Any]
contentView.addConstraints(NSLayoutConstraint.constraints(withVisualFormat: "V:|-[image(10)]", options: [], metrics: nil, views: viewsDict))
contentView.addConstraints(NSLayoutConstraint.constraints(withVisualFormat: "V:[labTime]-|", options: [], metrics: nil, views: viewsDict))
contentView.addConstraints(NSLayoutConstraint.constraints(withVisualFormat: "V:|-[username]-[message]-|", options: [], metrics: nil, views: viewsDict))
contentView.addConstraints(NSLayoutConstraint.constraints(withVisualFormat: "H:|-[username]-[image(10)]-|", options: [], metrics: nil, views: viewsDict))
contentView.addConstraints(NSLayoutConstraint.constraints(withVisualFormat: "H:|-[message]-[labTime]-|", options: [], metrics: nil, views: viewsDict))
required init?(coder aDecoder: NSCoder)
fatalError("init(coder:) has not been implemented")
Settigns.swift:
import Foundation
import UIKit
class Settings: UIViewController, UITableViewDelegate, UITableViewDataSource
private var myTableView: UITableView!
private let sections: NSArray = ["fruit", "vegitable"] //Profile network audio Codecs
private let fruit: NSArray = ["apple", "orange", "banana", "strawberry", "lemon"]
private let vegitable: NSArray = ["carrots", "avocado", "potato", "onion"]
override func viewDidLoad()
super.viewDidLoad()
// get width and height of View
let barHeight: CGFloat = UIApplication.shared.statusBarFrame.size.height
let navigationBarHeight: CGFloat = self.navigationController!.navigationBar.frame.size.height
let displayWidth: CGFloat = self.view.frame.width
let displayHeight: CGFloat = self.view.frame.height
myTableView = UITableView(frame: CGRect(x: 0, y: barHeight+navigationBarHeight, width: displayWidth, height: displayHeight - (barHeight+navigationBarHeight)))
myTableView.register(CustomTableViewCell.self, forCellReuseIdentifier: "cell") // register cell name
myTableView.dataSource = self
myTableView.delegate = self
//Auto-set the UITableViewCells height (requires iOS8+)
myTableView.rowHeight = UITableViewAutomaticDimension
myTableView.estimatedRowHeight = 44
self.view.addSubview(myTableView)
override func didReceiveMemoryWarning()
super.didReceiveMemoryWarning()
// return the number of sections
func numberOfSections(in tableView: UITableView) -> Int
return sections.count
// return the title of sections
func tableView(_ tableView: UITableView, titleForHeaderInSection section: Int) -> String?
return sections[section] as? String
// called when the cell is selected.
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath)
print("Num: \(indexPath.row)")
if indexPath.section == 0
print("Value: \(fruit[indexPath.row])")
else if indexPath.section == 1
print("Value: \(vegitable[indexPath.row])")
// return the number of cells each section.
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int
if section == 0
return fruit.count
else if section == 1
return vegitable.count
else
return 0
// return cells
public func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell
let cell = tableView.dequeueReusableCell(withIdentifier: "cell", for: indexPath) as! CustomTableViewCell
if indexPath.section == 0
cell.labUerName.text = "\(fruit[indexPath.row])"
cell.labMessage.text = "Message \(indexPath.row)"
cell.labTime.text = DateFormatter.localizedString(from: NSDate() as Date, dateStyle: .short, timeStyle: .short)
else if indexPath.section == 1
cell.labUerName.text = "\(vegitable[indexPath.row])"
cell.labMessage.text = "Message \(indexPath.row)"
cell.labTime.text = DateFormatter.localizedString(from: NSDate() as Date, dateStyle: .short, timeStyle: .short)
return cell
【讨论】:
只是想知道...您为什么决定使用init(style:)
而不是 Imanou Petit 使用的 awakeFromNib()
?有区别吗?
Imanou Petit 假设用户正在使用 Interface Builder。当我使用他的答案时,我使代码完全独立于任何故事板/xib = nib,因此在我的应用程序中永远不会调用 awakeFromNib()。顺便说一句,我还必须添加这一行: myTableView.register(CustomTableViewCell.self, forCellReuseIdentifier: "cell")
嘿@TiagoMendes 快速问题,我使用情节提要创建了一个自定义单元格,我试图通过一个插座在 cellForRowAtIndexPath 方法中更改其背景颜色,但它似乎不起作用。像 .isHidden 这样的属性可以正常工作。这是这样做的正确方法吗?我错过了什么吗?
这仍然是我在 Swift5 中的修复方法【参考方案3】:
在 Swift 5 中。
自定义 UITableViewCell:
import UIKit
class CourseCell: UITableViewCell
let courseName = UILabel()
override init(style: UITableViewCell.CellStyle, reuseIdentifier: String?)
super.init(style: style, reuseIdentifier: reuseIdentifier)
// Set any attributes of your UI components here.
courseName.translatesAutoresizingMaskIntoConstraints = false
courseName.font = UIFont.systemFont(ofSize: 20)
// Add the UI components
contentView.addSubview(courseName)
NSLayoutConstraint.activate([
courseName.leadingAnchor.constraint(equalTo: contentView.leadingAnchor, constant: 20),
courseName.bottomAnchor.constraint(equalTo: contentView.bottomAnchor, constant: -20),
courseName.trailingAnchor.constraint(equalTo: contentView.trailingAnchor, constant: -20),
courseName.heightAnchor.constraint(equalToConstant: 50)
])
required init?(coder: NSCoder)
fatalError("init(coder:) has not been implemented")
UITableViewController:
import UIKit
class CourseTableViewController: UITableViewController
private var data: [Int] = [1]
override func viewDidLoad()
super.viewDidLoad()
// You must register the cell with a reuse identifier
tableView.register(CourseCell.self, forCellReuseIdentifier: "courseCell")
// Change the row height if you want
tableView.rowHeight = 150
// This will remove any empty cells that are below your data filled cells
tableView.tableFooterView = UIView()
// MARK: - Table view data source
override func numberOfSections(in tableView: UITableView) -> Int
return 1
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int
return data.count
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell
let cell = tableView.dequeueReusableCell(withIdentifier: "courseCell", for: indexPath) as! CourseCell
cell.courseName.text = "Course name"
return cell
override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath)
tableView.deselectRow(at: indexPath, animated: true)
【讨论】:
以上是关于使用 Swift 以编程方式自定义 UITableViewCell的主要内容,如果未能解决你的问题,请参考以下文章
使用自定义初始化程序 swift 以编程方式实例化和推送视图控制器
如何以编程方式将自定义 uiview 添加到视图控制器 SWIFT