I\'m trying to build a titleView with constraints that looks like this:
I know how I would do
Thanks @Valentin Shergin and @tubtub! According to their answers I made an implementation of navigation bar title with dropdown arrow image in Swift 1.2:
UIView
subclass for custom titleView
translatesAutoresizingMaskIntoConstraints
to false
for subviews and true
for titleView
itself. b) Implement sizeThatFits(size: CGSize)
titleLabel.sizeToFit()
and self.setNeedsUpdateConstraints()
inside titleView
's subclass after text changesupdateTitleView()
and make sure to call titleView.sizeToFit()
and navigationBar.setNeedsLayout()
in thereHere's minimal implementation of DropdownTitleView
:
import UIKit
class DropdownTitleView: UIView {
private var titleLabel: UILabel
private var arrowImageView: UIImageView
// MARK: - Life cycle
override init (frame: CGRect) {
self.titleLabel = UILabel(frame: CGRectZero)
self.titleLabel.setTranslatesAutoresizingMaskIntoConstraints(false)
self.arrowImageView = UIImageView(image: UIImage(named: "dropdown-arrow")!)
self.arrowImageView.setTranslatesAutoresizingMaskIntoConstraints(false)
super.init(frame: frame)
self.setTranslatesAutoresizingMaskIntoConstraints(true)
self.addSubviews()
}
convenience init () {
self.init(frame: CGRectZero)
}
required init(coder aDecoder: NSCoder) {
fatalError("DropdownTitleView does not support NSCoding")
}
private func addSubviews() {
addSubview(titleLabel)
addSubview(arrowImageView)
}
// MARK: - Methods
func setTitle(title: String) {
titleLabel.text = title
titleLabel.sizeToFit()
setNeedsUpdateConstraints()
}
// MARK: - Layout
override func updateConstraints() {
removeConstraints(self.constraints())
let viewsDictionary = ["titleLabel": titleLabel, "arrowImageView": arrowImageView]
var constraints: [AnyObject] = []
constraints.extend(NSLayoutConstraint.constraintsWithVisualFormat("H:|[titleLabel]-8-[arrowImageView]|", options: .AlignAllBaseline, metrics: nil, views: viewsDictionary))
constraints.extend(NSLayoutConstraint.constraintsWithVisualFormat("V:|[titleLabel]|", options: NSLayoutFormatOptions(0), metrics: nil, views: viewsDictionary))
self.addConstraints(constraints)
super.updateConstraints()
}
override func sizeThatFits(size: CGSize) -> CGSize {
// +8.0 - distance between image and text
let width = CGRectGetWidth(arrowImageView.bounds) + CGRectGetWidth(titleLabel.bounds) + 8.0
let height = max(CGRectGetHeight(arrowImageView.bounds), CGRectGetHeight(titleLabel.bounds))
return CGSizeMake(width, height)
}
}
and ViewController:
override func viewDidLoad() {
super.viewDidLoad()
// Set custom title view to show arrow image along with title
self.navigationItem.titleView = dropdownTitleView
// your code ...
}
private func updateTitleView(title: String) {
// update text
dropdownTitleView.setTitle(title)
// layout title view
dropdownTitleView.sizeToFit()
self.navigationController?.navigationBar.setNeedsLayout()
}