0

I'm currently trying to use Auto-Layout constraints to vertically position a UIButton's TitleLabel below its ImageView. However, I can't seem to figure out how to remove the default constraints from the UIButton. Because of this, the final set of constraints is ambiguous. How can I remove the default constraints and make my constraints work? Also, I keep seeing people using insets to accomplish this layout. Why is this? Below is my code:

 public class DrawerButton : UIButton
{
    public override UIButtonType ButtonType { get; } = UIButtonType.Custom;

    public override void UpdateConstraints()
    {
        this.AddConstraints(
        ImageView.WithSameCenterX(this),

        TitleLabel.Below(ImageView).Plus(10),
        TitleLabel.WithSameCenterX(this)

        );

        base.UpdateConstraints();
    }

    public override void LayoutSubviews()
    {
        this.TranslatesAutoresizingMaskIntoConstraints = false;
        this.SubviewsDoNotTranslateAutoresizingMaskIntoConstraints();
        base.LayoutSubviews();
    }
}

Generated error:

2016-09-28 22:31:08.163 XXXXXXXXXXX[80361:7012489] Unable to simultaneously satisfy constraints.
    Probably at least one of the constraints in the following list is one you don't want. 
    Try this: 
        (1) look at each constraint and try to figure out which you don't expect; 
        (2) find the code that added the unwanted constraint or constraints and fix it. 
(
    "<NSLayoutConstraint:0x79292ca0 V:[UIImageView:0x78efb2c0]-(10)-[UIButtonLabel:0x78e00dc0'TEST']>",
    "<NSLayoutConstraint:0x792bb250 UIImageView:0x78efb2c0.centerY == XXXXXXXXX_iOS_Widgets_DrawerButton:0x793ddec0'TEST'.centerY>",
    "<NSLayoutConstraint:0x792c9310 UIButtonLabel:0x78e00dc0'TEST'.centerY == XXXXXXXXX_iOS_Widgets_DrawerButton:0x793ddec0'TEST'.centerY>"
)

Will attempt to recover by breaking constraint 
<NSLayoutConstraint:0x79292ca0 V:[UIImageView:0x78efb2c0]-(10)-[UIButtonLabel:0x78e00dc0'TEST']>
masterwok
  • 4,868
  • 4
  • 34
  • 41
  • Check this [Q&A](http://stackoverflow.com/questions/11664115/unable-to-simultaneously-satisfy-constraints-will-attempt-to-recover-by-breakin) first, if you are willing to. – pedrouan Sep 29 '16 at 06:33
  • I saw that, thanks. I know that there are conflicting constraints. The problem is that I do not know how to remove the default constraints. – masterwok Sep 29 '16 at 06:35
  • 1
    Consider changing the title of the question, as you know how to do that, but you're missing solution for an elementary issue. E.g. 'How to remove default constraints'. – pedrouan Sep 29 '16 at 06:40

2 Answers2

1

Here is an extension (Swift3) that will vertically position the titleLabel of a UIButton underneath the imageView.

extension UIButton {
    func centerButtonAndImageVertically(verticalSpacing: CGFloat = 0) {

        self.contentVerticalAlignment = .center
        self.contentHorizontalAlignment = .center

        let imageWidth = self.imageView?.frame.size.width ?? 0
        let imageHeight = self.imageView?.frame.size.height ?? 0
        let titleHeight = self.titleLabel?.frame.size.height ?? 0
        let titleWidth = self.titleLabel?.frame.size.width ?? 0

        self.imageEdgeInsets = UIEdgeInsets(top: 0, left: titleWidth, bottom: titleHeight+verticalSpacing*0.5, right: 0)
        self.titleEdgeInsets = UIEdgeInsets(top: imageHeight+verticalSpacing*0.5, left: 0, bottom: 0, right: imageWidth)
    }
}

As an example, I am using the extension in the following ViewController code to get the result as in the image:

class ViewController: UIViewController {

    @IBOutlet weak var smallButton: UIButton!
    @IBOutlet weak var button: UIButton!
    @IBOutlet weak var bigButton: UIButton!
    @IBOutlet weak var imageOnlyButton: UIButton!
    @IBOutlet weak var titleOnlyButton: UIButton!

    override func viewDidAppear(_ animated: Bool) {
        super.viewDidAppear(animated)
        smallButton.centerButtonAndImageVertically()
        button.centerButtonAndImageVertically()
        bigButton.centerButtonAndImageVertically(verticalSpacing: 10)
        imageOnlyButton.centerButtonAndImageVertically()
        titleOnlyButton.centerButtonAndImageVertically()
    }

}

example

Carien van Zyl
  • 2,853
  • 22
  • 30
1

Faced the same issue, didnt find the answer but for me solution that worked, was to override this UIButton's methods in my subclass:

override func imageRect(forContentRect contentRect: CGRect) -> CGRect {

    var imageFrame: CGRect = super.imageRect(forContentRect: contentRect)

    imageFrame.origin = CGPoint(x: bounds.midX - imageFrame.width / 2, y: bounds.midY - imageFrame.height)

    return imageFrame
}

override func titleRect(forContentRect contentRect: CGRect) -> CGRect {

    var titleFrame: CGRect = super.titleRect(forContentRect: contentRect)

    titleFrame.origin = CGPoint(x: bounds.midX - titleFrame.width / 2, y: bounds.midY)

    return titleFrame
}

Maybe it will help someone