Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

UIButton titleLabel frame size returning CGSize with zero width & height

Tags:

ios

ios8

For iOS7, I used the UIButton titleLabel.frame.size.width property to determine the width of my button title under different localisations so I could position the title correctly using contentInset on the UIButton.

My UIButton is setup with an image and title and I always want the combination of these two to be centred horizontally in the UIButton for example:

[space-x (image) space-y (titleLabel) space-x]

Under iOS 7 and Xcode 5.1, the following code works perfectly (even running on iOS 8 GM when built in XCode 5.1):

CGSize buttonSize = button.frame.size;
CGSize titleSize = button.titleLabel.frame.size;
float contentInset =((buttonSize.width - (titleSize.width + 18 + 3)) / 2 );
float contentInsetRounded = roundf(contentInset);
[button setContentEdgeInsets:(UIEdgeInsetsMake(0, contentInsetRounded, 0, 0))];

(18 is the width of the image, and 3 is the number of points spacing between the image and titleLabel or space-y in my example above)

Under iOS 8 and Xcode 6 GM, button.titleLabel.frame.size is returning a CGSize with zero width & height so my contentInset ends up centring the UIImage in the UIButton, causing the titleLabel to truncate.

Any ideas? I tried setting the titleLabel text immediately before this code in case it thought it was empty but that didn't help either.

Thanks in advance!

like image 845
staticnz Avatar asked Sep 10 '14 06:09

staticnz


3 Answers

Set the title text, then make a sizeToFit for the title label, and try to get the titleLabel.frame.size.width

[myButton setTitle:@"My Title" forState:UIControlStateNormal];
[myButton.titleLabel sizeToFit];
like image 133
Ricardo Garcia Avatar answered Nov 13 '22 14:11

Ricardo Garcia


I resolved it. App run on iOS8, build by Xcode 6, not update frame right after UIButton setTitle, setTitleEdgeInsets. It will wait for next UI update. So, if you get frame of titleLabel, you will get CGRectZero.

Solution:

  1. Call below methods after set UI property, to update layout immediately:

    [self setNeedsLayout];
    [self layoutIfNeeded];

Or:

  1. Delay a second, and you can get titleFrame, use self.titleLabel.frame.

Or:

  1. dispatch_async in main queue, to move code to next queue
like image 30
huync Avatar answered Nov 13 '22 15:11

huync


If you are then setting an image next to a button after getting the frame, you can use

[theButton setTitle: @"theTitle" forState:UIControlStateNormal];
[theButton setImage: theImage forState:UIControlStateNormal];
[theButton setNeedsLayout];
[theButton layoutIfNeeded];
[theButton setImageEdgeInsets: UIEdgeInsetsMake(6, transactionsButton.titleLabel.frame.size.width + 40.0, 0, 0)];

And in Swift 3, this will do.

self.view.layoutIfNeeded()
like image 2
Naishta Avatar answered Nov 13 '22 14:11

Naishta