Building a titleView programmatically with constraints (or generally constructing a view with constraints)

后端 未结 6 1814
长情又很酷
长情又很酷 2021-02-03 20:44

I\'m trying to build a titleView with constraints that looks like this:

\"titleView\"

I know how I would do

6条回答
  •  旧巷少年郎
    2021-02-03 21:37

    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:

    1. Create a UIView subclass for custom titleView
    2. In your subclass: a) Use auto layout for subviews but not for itself. Set translatesAutoresizingMaskIntoConstraints to false for subviews and true for titleView itself. b) Implement sizeThatFits(size: CGSize)
    3. If your title can change call titleLabel.sizeToFit() and self.setNeedsUpdateConstraints() inside titleView's subclass after text changes
    4. In your ViewController call custom updateTitleView() and make sure to call titleView.sizeToFit() and navigationBar.setNeedsLayout() in there

    Here'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()
    }
    

提交回复
热议问题