Multiline UIButton and autolayout

后端 未结 16 1452
无人共我
无人共我 2020-12-03 13:08

I have created a view controller that looks like this:

\"enter

I want the two

相关标签:
16条回答
  • 2020-12-03 13:40

    Complete class in Swift 3 - based on @Jan, @Quantaliinuxite and @matt bezark:

    @IBDesignable
    class MultiLineButton:UIButton {
    
        //MARK: -
        //MARK: Setup
        func setup () {
            self.titleLabel?.numberOfLines = 0
    
            //The next two lines are essential in making sure autolayout sizes us correctly
            self.setContentHuggingPriority(UILayoutPriorityDefaultLow+1, for: .vertical)
            self.setContentHuggingPriority(UILayoutPriorityDefaultLow+1, for: .horizontal)
        }
    
        //MARK:-
        //MARK: Method overrides
        required init?(coder aDecoder: NSCoder) {
            super.init(coder: aDecoder)
            setup()
        }
    
        override init(frame: CGRect) {
            super.init(frame: frame)
            setup()
        }
    
        override var intrinsicContentSize: CGSize {
            return self.titleLabel!.intrinsicContentSize
        }
    
        override func layoutSubviews() {
            super.layoutSubviews()
            titleLabel?.preferredMaxLayoutWidth = self.titleLabel!.frame.size.width
        }
    }
    
    0 讨论(0)
  • 2020-12-03 13:41

    There is a solution without subclassing on iOS11. Just need to set one additional constraint in code to match height of button and button.titleLabel.

    ObjC:

    // In init or overriden updateConstraints method
    NSLayoutConstraint *constraint = [NSLayoutConstraint constraintWithItem:self.button
                                                                  attribute:NSLayoutAttributeHeight
                                                                  relatedBy:NSLayoutRelationEqual
                                                                     toItem:self.button.titleLabel
                                                                  attribute:NSLayoutAttributeHeight
                                                                 multiplier:1
                                                                   constant:0];
    
    [self addConstraint:constraint];
    

    And in some cases (as said before):

    - (void)layoutSubviews {
        [super layoutSubviews];
    
        self.button.titleLabel.preferredMaxLayoutWidth = CGRectGetWidth(self.button.titleLabel.frame);
    }
    

    Swift:

    let constraint = NSLayoutConstraint(item: button,
                                        attribute: .height,
                                        relatedBy: .equal,
                                        toItem: button.titleLabel,
                                        attribute: .height,
                                        multiplier: 1,
                                        constant: 0)
    
    self.addConstraint(constraint)
    

    +

    override func layoutSubviews() {
        super.layoutSubviews()
    
        button.titleLabel.preferredMaxLayoutWidth = button.titleLabel.frame.width
    }
    
    0 讨论(0)
  • 2020-12-03 13:46

    Instead of calling layoutSubviews twice I'd calculate preferredMaxLayoutWidth manually

    @objcMembers class MultilineButton: UIButton {
    
    override var intrinsicContentSize: CGSize {
        // override to have the right height with autolayout
        get {
            var titleContentSize = titleLabel!.intrinsicContentSize
            titleContentSize.height += contentEdgeInsets.top + contentEdgeInsets.bottom
            return titleContentSize
        }
    }
    
    override func awakeFromNib() {
        super.awakeFromNib()
        titleLabel!.numberOfLines = 0
    }
    
    override func layoutSubviews() {
        let contentWidth = width - contentEdgeInsets.left - contentEdgeInsets.right
        let imageWidth = imageView?.width ?? 0 + imageEdgeInsets.left + imageEdgeInsets.right
        let titleMaxWidth = contentWidth - imageWidth - titleEdgeInsets.left - titleEdgeInsets.right
    
        titleLabel!.preferredMaxLayoutWidth = titleMaxWidth
        super.layoutSubviews()
    }
    }
    
    0 讨论(0)
  • 2020-12-03 13:47

    tweaks for Swift 3.1

    intrisicContentSize is a property instead of a function

    override var intrinsicContentSize: CGSize {
        return self.titleLabel!.intrinsicContentSize
    }
    
    0 讨论(0)
  • 2020-12-03 13:47

    None of the other answers had everything working for me. Here's my answer:

    class MultilineButton: UIButton {
        func setup() {
            titleLabel?.textAlignment = .center
            titleLabel?.numberOfLines = 0
            titleLabel?.lineBreakMode = .byWordWrapping
        }
    
        required init?(coder aDecoder: NSCoder) {
            super.init(coder: aDecoder)
            setup()
        }
    
        override init(frame: CGRect) {
            super.init(frame: frame)
            setup()
        }
    
        override var intrinsicContentSize: CGSize {
            var titleContentSize = titleLabel?.intrinsicContentSize ?? CGSize.zero
            titleContentSize.height += contentEdgeInsets.top + contentEdgeInsets.bottom
            titleContentSize.width += contentEdgeInsets.left + contentEdgeInsets.right
            return titleContentSize
        }
    
        override func layoutSubviews() {
            titleLabel?.preferredMaxLayoutWidth = 300 // Or whatever your maximum is
            super.layoutSubviews()
        }
    }
    

    This won't cater for an image, however.

    0 讨论(0)
  • 2020-12-03 13:47
    //Swift 4 - Create Dynamic Button MultiLine Dynamic
    
    class ViewController: UIViewController {
    
        override func viewDidLoad() {
            super.viewDidLoad()
    
             /// Add DemoButton 1
            let demoButton1 = buildButton("Demo 1")
            //demoButton1.addTarget(self, action: #selector(ViewController.onDemo1Tapped), for: .touchUpInside)
            view.addSubview(demoButton1)
    
            view.addConstraint(NSLayoutConstraint(item: demoButton1, attribute: .centerX, relatedBy: .equal, toItem: view, attribute: .centerX, multiplier: 1, constant: 0))
            view.addConstraint(NSLayoutConstraint(item: demoButton1, attribute: .centerY, relatedBy: .equal, toItem: view, attribute: .centerY, multiplier: 1, constant: -180))
    
        }
    
        func buildButton(_ title: String) -> UIButton {
            let button = UIButton(type: .system)
            button.backgroundColor = UIColor(red: 80/255, green: 70/255, blue: 66/255, alpha: 1.0)
    
            //--------------------------
            //to make the button multiline
            //button.titleLabel!.lineBreakMode = .byWordWrapping
            button.titleLabel?.textAlignment = .center
            button.titleLabel?.numberOfLines = 0
            //button.titleLabel?.adjustsFontSizeToFitWidth = true
            //button.sizeToFit()
            button.titleLabel?.preferredMaxLayoutWidth = self.view.bounds.width//200
            button.layer.borderWidth = 2
            let height = NSLayoutConstraint(item: button,
                                            attribute: .height,
                                            relatedBy: .equal,
                                            toItem: button.titleLabel,
                                            attribute: .height,
                                            multiplier: 1,
                                            constant: 0)
            button.addConstraint(height)
            //--------------------------
    
            button.setTitle(title, for: UIControlState())
            button.layer.cornerRadius = 4.0
            button.setTitleColor(UIColor(red: 233/255, green: 205/255, blue: 193/255, alpha: 1.0), for: UIControlState())
            button.translatesAutoresizingMaskIntoConstraints = false
            return button
        }
    }
    
    0 讨论(0)
提交回复
热议问题