Я хочу иметь вид нижнего колонтитула UITableView со статической ячейкой, который имеет три метки, которые расположены на одинаковом расстоянии друг от друга, например (из симулятора):
Я могу предоставить представление нижнего колонтитула из моего контроллера табличного представления, используя этот вызов делегата:
override func tableView(tableView: UITableView, viewForFooterInSection section: Int) -> UIView? {
// construct view here
return view
}
И я могу построить представление двумя способами:
- Создайте метки и разделители в коде и добавьте соответствующие ограничения.
- Сделайте все это в файле XIB, затем загрузите представление из файла.
Моя проблема в том, что первый подход не работает, а второй работает.
Это мой код для первого подхода:
override func tableView(tableView: UITableView, viewForFooterInSection section: Int) -> UIView? {
if section == 0 {
// Create footer view
let view = UIView()
view.backgroundColor = UIColor.yellowColor()
view.clipsToBounds = false
view.layer.borderColor = UIColor.greenColor().CGColor
view.layer.borderWidth = 2
view.setTranslatesAutoresizingMaskIntoConstraints(false)
// Create labels
var labels: [UIView] = []
for name in ["Label 1", "AAAAAABBB", "Last label"] {
let v = UILabel()
v.font = UIFont.preferredFontForTextStyle(UIFontTextStyleFootnote)
v.textColor = UIColor.darkTextColor()
v.textAlignment = .Center
v.text = name
v.setTranslatesAutoresizingMaskIntoConstraints(false)
view.addSubview(v)
labels += [v]
}
// Create spacers
var spacers: [UIView] = []
for i in 1...4 {
let v = UIView()
v.backgroundColor = UIColor.blueColor() // Background color is just so we can see where the view is and what size it has
v.setTranslatesAutoresizingMaskIntoConstraints(false)
view.addSubview(v)
spacers += [v]
}
// Constrain all views to top and bottom of superview
for i in labels + spacers {
view.addConstraint(NSLayoutConstraint(item: i, attribute: .Top, relatedBy: .Equal, toItem: view, attribute: .Top, multiplier: 1, constant: 0))
view.addConstraint(NSLayoutConstraint(item: i, attribute: .Bottom, relatedBy: .Equal, toItem: view, attribute: .Bottom, multiplier: 1, constant: 0))
}
// Equal width for labels
labels.pairs {
view.addConstraint(NSLayoutConstraint(item: $0, attribute: .Width, relatedBy: .Equal, toItem: $1, attribute: .Width, multiplier: 1, constant: 0))
}
// Equal width for spacers
spacers.pairs {
view.addConstraint(NSLayoutConstraint(item: $0, attribute: .Width, relatedBy: .Equal, toItem: $1, attribute: .Width, multiplier: 1, constant: 0))
}
view.addConstraint(NSLayoutConstraint(item: view, attribute: .Left, relatedBy: .Equal, toItem: spacers[0], attribute: .Left, multiplier: 1, constant: 0))
view.addConstraint(NSLayoutConstraint(item: spacers[0], attribute: .Right, relatedBy: .Equal, toItem: labels[0], attribute: .Left, multiplier: 1, constant: 0))
view.addConstraint(NSLayoutConstraint(item: labels[0], attribute: .Right, relatedBy: .Equal, toItem: spacers[1], attribute: .Left, multiplier: 1, constant: 0))
view.addConstraint(NSLayoutConstraint(item: spacers[1], attribute: .Right, relatedBy: .Equal, toItem: labels[1], attribute: .Left, multiplier: 1, constant: 0))
view.addConstraint(NSLayoutConstraint(item: labels[1], attribute: .Right, relatedBy: .Equal, toItem: spacers[2], attribute: .Left, multiplier: 1, constant: 0))
view.addConstraint(NSLayoutConstraint(item: spacers[2], attribute: .Right, relatedBy: .Equal, toItem: labels[2], attribute: .Left, multiplier: 1, constant: 0))
view.addConstraint(NSLayoutConstraint(item: labels[2], attribute: .Right, relatedBy: .Equal, toItem: spacers[3], attribute: .Left, multiplier: 1, constant: 0))
view.addConstraint(NSLayoutConstraint(item: spacers[3], attribute: .Right, relatedBy: .Equal, toItem: view, attribute: .Right, multiplier: 1, constant: 0))
return view
}
else {
return nil
}
}
extension Array {
func pairs(block: (Element, Element?)->()) {
if count == 0 { return }
if count == 1 { block(self.first!, nil) }
var last = self[0]
for i in self[1..<count] {
block(last, i)
last = i
}
}
}
Вот результат:
Совсем не то, что я ожидал, правда?
Теперь о втором методе. Вместо того, чтобы публиковать кучу скриншотов из Interface Builder, я создал пример проекта, доступный здесь специально для проверки этой проблемы. Если вы откроете его, файл FooterView.xib
содержит представление нижнего колонтитула, созданное в IB, которое, насколько мне известно, имеет точно такую же структуру представления и ограничения автоматического макета.
Используя это представление, например так:
return (NSBundle.mainBundle().loadNibNamed("FooterView", owner: self, options: nil).first as UIView)
дает результат, который вы видели на первом снимке экрана, и это именно то, что я хочу.
Таким образом, в Interface Builder ограничения работают так, как ожидалось. Почему это не работает, когда представления и ограничения создаются в коде? Что я упускаю?