简体   繁体   中英

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;

在此输入图像描述在此输入图像描述

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];

在此输入图像描述在此输入图像描述

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.

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.

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];

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:.".

在此输入图像描述

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];
    }
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM