jvergeldedios
jvergeldedios

Reputation: 637

Intrinsic size not updating when changing UIButton state

I have a UIView that contains a UIButton. The UIButton has 2 titles set for the UIControlStateNormal ("Follow") and UIControlStateSelected ("Following") states. I am using auto layout on the UIButton and it has a constraint to be a certain distance from the top of the superview and another to be a certain distance from the left side of the superview. I've also used "Size to fit Content" on it.

When I set the button to be in the selected state from code, the title changes correctly but the intrinsic width of the UIButton doesn't change so that when changing from "Follow" to "Following" the text gets ellipsized.

self.selected = self.following;

enter image description hereenter image description here

When I approach the problem differently and simply change the text for UIControlStateNormal when someone hits the button, the button changes size correctly.

NSString *title = (self.following) ? @"Following" : @"Follow"
[self setTitle:title forState:UIControlStateNormal];

enter image description hereenter image description here

Is this a bug in UIKit? I would expect the button to change its intrinsic size to correctly reflect the new size of the text when its state changes especially because there are other things I would like to change besides just the text for the 2 button states.

Upvotes: 12

Views: 8661

Answers (4)

SmileBot
SmileBot

Reputation: 19642

For me setting the contentEdgeInsets gave me the only reliable solution.

I'm using custom buttons, with background images. So, slices come into the picture. It turns out that how you slice images can also affect intrinsic content size! Test it! So, I had to make sure I was slicing identically between images for different states. I'm also using attributed strings. The solutions posted here didn't work for my case.

What I found after a day(!) of experimenting is that setting sufficient contentEdgeInsets values on the button makes it behave correctly when titles are changed using autolayout. There's no need to invalidate intrinsic content size or call any layout code if you do this.

You can either set the contentEdgeInsets in code or in IB.

self.button.contentEdgeInsets = UIEdgeInsetsMake(10.0, 16.0, 10.0, 16.0);

I think the Swift code is identical except for the var attribute.

Apple says this in the docs: "The button uses this property to determine intrinsicContentSize and sizeThatFits:.".

enter image description here

Upvotes: 1

akelagercrantz
akelagercrantz

Reputation: 310

Like David Caunt pointed out in a comment, calling invalidateIntrinsicContentSize will cause autolayout to resize the button to fit it's new content.

self.selected = self.following;
[self invalidateIntrinsicContentSize];

PS. David, if you want to post your commant as an answer I will remove mine.

Upvotes: 25

rdelmar
rdelmar

Reputation: 104082

Whether this is a bug, or just the way it is, I don't know, but it looks like you'll have to work around it -- I don't think you're doing anything wrong. If you want to toggle between selected and not after each touch, you could do something like this:

- (IBAction)buttonClick:(UIButton *)sender {
    sender.selected = !sender.selected;
    if (sender.selected) {
        [self.button setTitle:@"Following" forState:UIControlStateNormal];
        //Do whatever else you want to do here for the selected state
    }else{
        [self.button setTitle:@"Follow" forState:UIControlStateNormal];
    }
}

Upvotes: 0

Abdullah Shafique
Abdullah Shafique

Reputation: 6918

In your storyboard select your UIButton and on top select editor->size to fit content size.

EDIT: Try this:

[self.myButton setTitle:@"Following" forState:UIControlStateSelected];
[self.myButton sizeToFit];

Upvotes: 0

Related Questions