Incorrectly rendered UIButton’s image property using asset catalog and size classes

693 views Asked by At

I’m having an issue with UIButton’s image property. My asset catalog contains default images for Any / Any size class and images specific to Regular / Regular class. When I set UIButton’s image property in Interface Builder to “img_facebook” then the image is rendered incorrectly on iPad (image for Any / Any size is chosen instead of Regular / Regular one). But when I refresh it inside “traitCollectionDidChange:” method then the image is rendered correctly (see the attached code snippet).

- (void)traitCollectionDidChange:(UITraitCollection *)previousTraitCollection
{
    [super traitCollectionDidChange:previousTraitCollection];
    [_facebookButton setImage:[UIImage imageNamed:@"img_facebook"] forState:UIControlStateNormal];
}

It looks like IB creates an UIImage instance and assigns it to the property only once. It would make sense, but if I do the same with UIImage instead of UIButton everything works perfectly fine.

Has anyone experienced similar issue? Is it possible to fix that in IB or do I have to manually reset image in code?

2

There are 2 answers

2
Nick Kuh On

I've just come up against a similar problem. It appears to be a bug with UIButton. I've checked the traitCollection property of my button (added to a regular view controller view via Interface Builder):

<UITraitCollection: 0x7ff6f27a8930; _UITraitNameUserInterfaceIdiom = Phone, _UITraitNameDisplayScale = 2.000000>

It's missing the expected size classes. Eg, the parent view traitCollection looks like this:

<UITraitCollection: 0x7ff6f48a1640; _UITraitNameUserInterfaceIdiom = Phone, _UITraitNameDisplayScale = 2.000000, _UITraitNameHorizontalSizeClass = Compact, _UITraitNameVerticalSizeClass = Regular, _UITraitNameTouchLevel = 0, _UITraitNameInteractionModel = 1>

The easiest workaround is to modify your UIImageAsset to use the Device Specific option instead of the size classes:

enter image description here

And add iPhone and iPad specific images. That solved it for me (Xcode Beta 6.3)

0
Vincent On

I have the same issue, the only way i found is to use another api to set the proper image for button.

UIImage *image;
if ( NSClassFromString(@"UITraitCollection") ) { //need to support iOS7
    image = [UIImage imageNamed:@"xxx" inBundle:nil compatibleWithTraitCollection:self.traitCollection];
} else {
    image = [UIImage imageNamed:@"xxx"];
}
[button setImage:image forState:UIControlStateNormal];

From my testing, it seems the image of button will only be changed to corresponding trait automatically when the traitCollectionDidChange get called on a button. Which means if you want to manually control the image of button, you have to get the right trait image when set image to button otherwise you will need to wait next traitCollectionDidChange happen to button to get the image change automatically.