lindon fox
lindon fox

Reputation: 3318

How can I programmatically set the vertical alignment of a UIButton - iOS

I know how to set the vertical alignment of a button with IB; see here. But I can not do it programmatically... This is one of the things I have tried:

UIButton *button  = [[UIButton alloc] initWithFrame:CGRectMake(10, 10, 110, 130)];
[button setTitle:@"Align" forState:UIControlStateNormal];
button.backgroundColor = [UIColor whiteColor];
button.titleLabel.textColor = [UIColor grayColor];
[button setContentVerticalAlignment:UIControlContentVerticalAlignmentBottom];

[self.view addSubview:button];

[button release];

I have also tried insets...

But the alignment won't change.

Please note that I want to keep the CustomStyle of the button (I don't want the default look and feel).

Upvotes: 24

Views: 35853

Answers (6)

C0D3
C0D3

Reputation: 6559

I've tried the UIEdgeInset changes that are described above but they ended up breaking the LayoutConstraints for my view. So I came up with another solution which is subclassing the UIButton and adding a UILabel to the bottom of it and attaching constraints to that. Here is my solution if anyone wants to go this route:

class VerticalButton: UIButton {

lazy var verticalTitleLabel: UILabel = {
    let label = UILabel().autolayout()
    label.font = ScaledFont.shared.font(forTextStyle: .body)
    label.numberOfLines = 0
    label.textColor = .white
    return label
}()

required init?(coder: NSCoder) {
    super.init(coder: coder)
    commonInit()
}

override init(frame: CGRect) {
    super.init(frame: frame)
    commonInit()
}

convenience init(title: String) {
    self.init(frame: .zero)
    verticalTitleLabel.text = title
}

private func commonInit() {
    setTitle(nil, for: .normal)  // Set the original title to nil so it doesn't show
    addSubview(verticalTitleLabel)
    NSLayoutConstraint.activate([
        verticalTitleLabel.bottomAnchor.constraint(equalTo: bottomAnchor),
        verticalTitleLabel.centerXAnchor.constraint(equalTo: centerXAnchor),
        verticalTitleLabel.heightAnchor.constraint(greaterThanOrEqualToConstant: 25.0)
    ])
}

override func setTitle(_ title: String?, for state: UIControl.State) {
    super.setTitle("", for: state)
    verticalTitleLabel.text = title
}
}

Upvotes: 0

cynistersix
cynistersix

Reputation: 1215

I found a better way that works for me. I'm using a custom font so the alignment went a bit off by a few like in lindon fox's answer above.

Inside of you UIButton subclass:

- (void)layoutSubviews {

      [super layoutSubviews];

      if (UIEdgeInsetsEqualToEdgeInsets(UIEdgeInsetsZero, self.titleEdgeInsets)) {

            // adjust top, left bottom, and right to fit your needs
            self.titleEdgeInsets = UIEdgeInsetsMake(top, left, bottom, right);
      }
}

I agree with the other answers that using the contentVerticalAlignment set to UIControlContentVerticalAlignmentCenter is also a good idea.

Upvotes: 0

Alessandro Pirovano
Alessandro Pirovano

Reputation: 2551

You can alignment (horizontal and vertical) the text of button in this way:

        UIButton *button  = [[UIButton alloc] initWithFrame:CGRectMake(0, 0, 200, 70)];
        button.backgroundColor = [UIColor whiteColor];
        button.contentHorizontalAlignment = UIControlContentHorizontalAlignmentLeft;
        button.contentVerticalAlignment = UIControlContentVerticalAlignmentBottom;
        [button setTitle:@"Align" forState:UIControlStateNormal];
        [self.container addSubview:button];

Upvotes: 27

Dmitry Lezhnev
Dmitry Lezhnev

Reputation: 884

You can easily manipulate inner text label of UIButton. Here how you can do it:

  1. set buttons's text to @"" (empty string)
  2. create new UILabel and adjust it's frame
  3. insert created UILabel inside buttons's view as subview
  4. It's done. Now you can programmatically set position of inner UILabel with changing it's frame property.

Upvotes: 1

lindon fox
lindon fox

Reputation: 3318

The problem was the using

button.titleLabel.textColor = [UIColor grayColor];

instead of

[button setTitleColor:[UIColor blackColor] forState:UIControlStateNormal];

Elsewhere in my code I am still having troubles vertically aligning the text, but I have got the basic example going, so I should be able to get the more complicated version going if I look at it more. Perhaps there are other methods I am using like button.titleLabel.textColor which make the vertical alignment not work...

Update The original problem was actually because my button was too short (button height).

The word `husband' is in the button

The word husband is in the button, which is currently vertically aligned to the bottom. But since the height of the button is not enough, it is not obvious. Even though the default of the title insets and content insets are zero, it does not seem like the title can be flush against the bottom. It looks like about 5 pixels to me. I tested with a smaller font to make sure this is correct.

Unfortunately vertically aligning the text to the top does not seem to change anything...

Upvotes: 1

XJones
XJones

Reputation: 21967

contentVerticalAlignment is the way to go. Could be how you're creating the button. Try this:

 UIButton *button = [UIButton buttonWithType:UIButtonTypeRoundedRect];
 button.frame = CGRectMake(10, 10, 110, 130);
 // rest of your code
 // don't release button explicitly

Upvotes: 9

Related Questions