我可以在编程上创建简单的自定义viewForHeaderInSection,如下所示。但我想做更复杂的事情,可能是与不同的类连接,并像tableView单元格一样到达它们的属性。简单地说,我想看看我做了什么。
func tableView(tableView: UITableView, viewForHeaderInSection section: Int) -> UIView? {
if(section == 0) {
let view = UIView() // The width will be the same as the cell, and the height should be set in tableView:heightForRowAtIndexPath:
let label = UILabel()
let button = UIButton(type: UIButtonType.System)
label.text="My Details"
button.setTitle("Test Title", forState: .Normal)
// button.addTarget(self, action: Selector("visibleRow:"), forControlEvents:.TouchUpInside)
view.addSubview(label)
view.addSubview(button)
label.translatesAutoresizingMaskIntoConstraints = false
button.translatesAutoresizingMaskIntoConstraints = false
let views = ["label": label, "button": button, "view": view]
let horizontallayoutContraints = NSLayoutConstraint.constraintsWithVisualFormat("H:|-10-[label]-60-[button]-10-|", options: .AlignAllCenterY, metrics: nil, views: views)
view.addConstraints(horizontallayoutContraints)
let verticalLayoutContraint = NSLayoutConstraint(item: label, attribute: .CenterY, relatedBy: .Equal, toItem: view, attribute: .CenterY, multiplier: 1, constant: 0)
view.addConstraint(verticalLayoutContraint)
return view
}
return nil
}
func tableView(tableView: UITableView, heightForHeaderInSection section: Int) -> CGFloat {
return 50
}
有没有人解释如何使用xib创建自定义tableView标题视图?我遇到过旧的Obj-C主题,但我是Swift语言的新手。如果有人解释详细,那就太好了。
1.issue:按钮@IBAction无法与我的ViewController连接。的(固定)
使用File的Owner,ViewController基类解决(点击左侧轮廓菜单。)
2.issue:标题高度问题(已修复)
解决了在 viewForHeaderInSection :方法中添加 headerView.clipsToBounds = true 的问题。
对于约束警告 this answer solved my problems:
当我在viewController中使用此方法添加ImageView甚至相同的高度约束时,它会流过tableView行look like picture。
func tableView(tableView: UITableView, heightForHeaderInSection section: Int) -> CGFloat {
return 120
}
如果我使用,则在viewDidLoad中自动调整ScrollViewInsets,在这种情况下,图像流在navigationBar下。 -fixed -
self.automaticallyAdjustsScrollViewInsets = false
3.issue:如果按下(已修复)
下的按钮
@IBAction func didTapButton(sender: AnyObject) {
print("tapped")
if let upView = sender.superview {
if let headerView = upView?.superview as? CustomHeader {
print("in section \(headerView.sectionNumber)")
}
}
}
答案 0 :(得分:76)
基于NIB的标头的典型过程是:
创建UITableViewHeaderFooterView
子类,至少使用标签的插座。您可能还想给它一些标识符,通过该标识符可以对此标题对应的部分进行反向工程。同样,您可能希望指定一个协议,标头可以通过该协议通知视图控制器事件(如点击按钮)。因此,在Swift 3及更高版本中:
// if you want your header to be able to inform view controller of key events, create protocol
protocol CustomHeaderDelegate: class {
func customHeader(_ customHeader: CustomHeader, didTapButtonInSection section: Int)
}
// define CustomHeader class with necessary `delegate`, `@IBOutlet` and `@IBAction`:
class CustomHeader: UITableViewHeaderFooterView {
static let reuseIdentifier = "CustomHeader"
weak var delegate: CustomHeaderDelegate?
@IBOutlet weak var customLabel: UILabel!
var sectionNumber: Int! // you don't have to do this, but it can be useful to have reference back to the section number so that when you tap on a button, you know which section you came from; obviously this is problematic if you insert/delete sections after the table is loaded; always reload in that case
@IBAction func didTapButton(_ sender: AnyObject) {
delegate?.customHeader(self, didTapButtonInSection: section)
}
}
创建NIB。就个人而言,我给NIB提供了与基类相同的名称,以简化我项目中文件的管理,避免混淆。无论如何,关键步骤包括:
创建视图NIB,或者如果您使用空NIB开始,请将视图添加到NIB;
将视图的基类设置为UITableViewHeaderFooterView
子类的任何内容(在我的示例中为CustomHeader
);
在IB中添加控件和约束;
将您的Swift代码中的商店引用@IBOutlet
引用;
将按钮连接到@IBAction
;以及
对于NIB中的根视图,请确保将背景颜色设置为"默认"否则你会收到有关改变背景颜色的恼人警告。
在视图控制器的viewDidLoad
中,注册NIB。在Swift 3及更高版本中:
override func viewDidLoad() {
super.viewDidLoad()
tableView.register(UINib(nibName: "CustomHeader", bundle: nil), forHeaderFooterViewReuseIdentifier: CustomHeader.reuseIdentifier)
}
在viewForHeaderInSection
中,使用您在上一步中指定的相同标识符将可重用视图出列。完成后,您现在可以使用您的插座,您不必对编程创建的约束等做任何事情。您需要做的唯一事情(对于按钮工作的协议)是指定其委托。例如,在Swift 3中:
override func tableView(_ tableView: UITableView, viewForHeaderInSection section: Int) -> UIView? {
let headerView = tableView.dequeueReusableHeaderFooterView(withIdentifier: "CustomHeader") as! CustomHeader
headerView.customLabel.text = content[section].name // set this however is appropriate for your app's model
headerView.sectionNumber = section
headerView.delegate = self
return headerView
}
override func tableView(_ tableView: UITableView, heightForHeaderInSection section: Int) -> CGFloat {
return 44 // or whatever
}
显然,如果您要在标题视图中将视图控制器指定为按钮的delegate
,则必须符合该协议:
extension ViewController: CustomHeaderDelegate {
func customHeader(_ customHeader: CustomHeader, didTapButtonInSection section: Int) {
print("did tap button", section)
}
}
当我列出所涉及的所有步骤时,这一切听起来都很混乱,但是一旦你完成了一两次,它就会变得非常简单。我认为它比以编程方式构建标题视图更简单。
在matt's answer,他抗议:
问题很简单,就是你不能仅仅通过在身份检查器中声明它,将一个笔尖中的
UIView
神奇地变成UITableViewHeaderFooterView
。
这根本不正确。如果使用上述基于NIB的方法,则为此标头视图的根视图实例化的类是 UITableViewHeaderFooterView
子类,而不是UIView
。它实例化您为NIB根视图为基类指定的任何类。
但是,正确的是,此类的某些属性(尤其是contentView
)并未在此基于NIB的方法中使用。它应该是可选属性,就像textLabel
和detailTextLabel
一样(或者更好的是,它们应该在IB中为UITableViewHeaderFooterView
添加适当的支持)。我同意这在Apple的设计上是糟糕的设计,但它让我觉得这是一个草率的,特殊的细节,但考虑到表格视图中的所有问题,这是一个小问题。例如,经过这么多年,我们仍然无法在故事板中进行原型页眉/页脚视图,并且必须完全依赖于这些NIB和类注册技术。
但是,如果不能使用register(_:forHeaderFooterViewReuseIdentifier:)
,这是一种自iOS 6以来一直在使用的API方法,这是不正确的。让我们不要把婴儿扔出洗澡水。
请参阅此答案的previous revision以获取Swift 2格式。
答案 1 :(得分:28)
问题很简单,就是你不能仅仅通过在身份检查器中声明它,将nib中的UIView变成UITableViewHeaderFooterView。 UITableViewHeaderFooterView具有对其正确操作至关重要的重要功能,并且无论您如何投射它都缺乏简单的UIView。
UITableViewHeaderFooterView有contentView
,所有自定义子视图都必须添加到此,而不是UITableViewHeaderFooterView。
但是作为UITableViewHeaderFooterView神秘地投射的UIView在笔尖中缺少这个contentView
。因此,当Rob说"在IB"中添加您的控件和约束时,他会让您将子视图直接添加到UITableViewHeaderFooterView ,而不添加到其{ {1}}。因此,标题最终配置错误。
此问题的另一个迹象是您不允许为UITableViewHeaderFooterView提供背景颜色。如果您这样做,您将在控制台中收到此消息:
不推荐在UITableViewHeaderFooterView上设置背景颜色。请将具有所需背景颜色的自定义UIView设置为backgroundView属性。
但是在笔尖中,你不能帮助在UITableViewHeaderFooterView上设置背景颜色,而你做在控制台中获取该消息。
那么问题的正确答案是什么?那里的没有可能的答案。苹果在这里做了很大的努力。他们提供了一种方法,允许您将nib注册为UITableViewHeaderFooterView的源,但对象库中没有UITableViewHeaderFooterView 。因此,此方法无用。在笔尖中正确设计UITableViewHeaderFooterView是不可能的。
这是Xcode中的一个巨大错误。我在2013年提交了关于此事的错误报告,它仍然坐在那里,打开。我年复一年地改变了这个错误,并且苹果不断推回,并且说#34;尚未确定如何或何时解决问题。"所以他们承认这个错误,但他们什么都不做。
可以做什么,但是,在nib中设计一个普通的UIView,然后在代码中(在contentView
的实现中),从笔尖手动加载视图并将其填入标题视图的viewForHeaderInSection
。
例如,我们假设我们要在笔尖中设计标题,并且我们在标题中有一个标签,我们要将其连接到插座contentView
。然后我们需要一个自定义头类和一个自定义视图类:
lab
我们注册了标题视图类,而不是nib:
class MyHeaderView : UITableViewHeaderFooterView {
weak var content : MyHeaderViewContent!
}
class MyHeaderViewContent : UIView {
@IBOutlet weak var lab : UILabel!
}
在视图 xib 文件中,我们将视图声明为MyHeaderViewContent - 而不是一个MyHeaderView。
在self.tableView.register(MyHeaderView.self,
forHeaderFooterViewReuseIdentifier: self.headerID)
中,我们从nib中取出视图,将其填入标题的viewForHeaderInSection
,然后配置对它的引用:
contentView
这是可怕而烦人的,但这是你能做的最好的事情。
答案 2 :(得分:4)
创建一个UITableViewHeaderFooterView及其对应的xib文件。
class BeerListSectionHeader: UITableViewHeaderFooterView {
@IBOutlet weak var sectionLabel: UILabel!
@IBOutlet weak var abvLabel: UILabel!
}
注册笔尖类似于注册表格视图单元格的方式。笔尖名称和重用标识符应与您的文件名匹配。 (xib没有重用ID。)
func registerHeader {
let nib = UINib(nibName: "BeerListSectionHeader", bundle: nil)
tableView.register(nib, forHeaderFooterViewReuseIdentifier: "BeerListSectionHeader")
}
出队并类似于使用单元格。标识符是文件名。
override func tableView(_ tableView: UITableView, viewForHeaderInSection section: Int) -> UIView? {
let header = tableView.dequeueReusableHeaderFooterView(withIdentifier: "BeerListSectionHeader") as! BeerListSectionHeader
let sectionTitle = allStyles[section].name
header.sectionLabel.text = sectionTitle
header.dismissButton?.addTarget(self, action: #selector(dismissView), for: .touchUpInside)
return header
}
别忘了页眉的高度。
override func tableView(_ tableView: UITableView, heightForHeaderInSection section: Int) -> CGFloat {
return BeerListSectionHeader.height
}
答案 3 :(得分:2)
我的信誉不足,无法向马特答案添加评论。
无论如何,这里唯一缺少的是在添加新视图之前从UITableViewHeaderFooterView.contentView中删除所有子视图。这样会将重用的单元格重置为初始状态,并避免内存泄漏。