6

I'm trying to give my UIButton a new background image when the user pressed the button and then animate the width. Problem is that the button doesn't scale the image (I'm only using retina images).

Before click:

enter image description here

After click:

enter image description here

And the code that makes things happen:

UIImage *buttonProfileDefault = [[UIImage imageNamed:@"Profile_Button_Default"] resizableImageWithCapInsets:UIEdgeInsetsMake(3, 3, 3, 3)];
        [self.profileButton setBackgroundImage:buttonProfileDefault forState:UIControlStateNormal];

[self.profileButton removeConstraint:self.profileButtonConstraint];

// Animate
CGRect originalFrame = self.profileButton.frame;
originalFrame.size.width = 40;
[UIView animateWithDuration:0.2f
    animations:^{
        self.profileButton.frame = originalFrame;
    }
        completion:^(BOOL finished) {
    }];
Holger Sindbaek
  • 2,278
  • 6
  • 41
  • 68
  • I hope we can figure this out: I have the same problem. I have tried all of the contentMode options and all of the imageEdgeInsets (for those I moved my background image into the button's image, which covers or eliminates the button title) all to no avail. – tobinjim Nov 30 '12 at 17:09
  • I'll put a bounty on this. Really need to know it. – Holger Sindbaek Dec 01 '12 at 04:14
  • @HolgerEdwardWardlowSindbæk try my code ... – Paras Joshi Dec 06 '12 at 13:14

8 Answers8

3

try this code...

    [UIView beginAnimations:nil context:NULL];
    [UIView setAnimationDuration:1.0];
    [self.profileButton setBackgroundImage:[UIImage imageNamed:@"Profile_Button_Default"] forState:UIControlStateNormal];
    [self.profileButton setBackgroundImage:[UIImage imageNamed:@"Profile_Button_Default"] forState:UIControlStateSelected];
    [self.profileButton setFrame:CGRectMake(self.profileButton.frame.origin.x, self.profileButton.frame.origin.y, self.profileButton.frame.size.width + 40, self.profileButton.frame.size.height)];
    [UIView commitAnimations];

i hope this help you...

Paras Joshi
  • 20,427
  • 11
  • 57
  • 70
2

The way you are creating the Edge Insets, would keep the leftmost 3 and the rightmost 3 poins (or pixels) constant, and it would stretch the head on the button. If you want the head's size to be constant, you have to include it in the left side, leave 1 pixel stretchable and then comes the right side. Assuming your picture's width is 50, you would write:

UIImage * buttonProfileDefault = [[UIImage imageNamed:@"Profile_Button_Default"] resizableImageWithCapInsets:UIEdgeInsetsMake(3, 46, 3, 3)];

However, this would make your picture positioned in the left side of the button. The solution I recommend would be to use 2 images:

  1. a resizable image containing only the border of the button, set as the button's background image
  2. an image containing only the head, set as the buttons image with constant size

The code would look something like:

UIImage *backgroundImage = [[UIImage imageNamed:@"border.png"] resizableImageWithCapInsets:UIEdgeInsetsMake(3, 3, 3, 3)]; // in this case you can use 3, 3, 3, 3

[self.profileButton setBackgroundImage:backgroundImage forState:UIControlStateNormal];

UIImage *titleImage = [UIImage imageNamed:@"head.png"];

[self.profileButton setImage:titleImage forState:UIControlStateNormal];

Hope this helps!

Levi
  • 7,313
  • 2
  • 32
  • 44
  • That's a very good observation. It's not the problem though. In the start, I switched the background image to one that didn't have a head (problem solved there), but it didn't use the cap-inset, so the edges got twisted and weird. That's the problem! Thanks for the input though. – Holger Sindbaek Dec 03 '12 at 07:14
  • What is the original size of your image? – Levi Dec 03 '12 at 09:26
  • 70 x 58 (I only use the retina version for both retina and non-retina iPhones) – Holger Sindbaek Dec 03 '12 at 09:57
2

I have modified your code on following points:

  • provided complete name of image Profile_Button_Default.png (or .jpg etc),
  • added states for image as in case of normal it these effects will not be appeared in starting of button touched

Now Check:

UIImage *buttonProfileDefault = [[UIImage imageNamed:@"Profile_Button_Default.png"] resizableImageWithCapInsets:UIEdgeInsetsMake(3, 3, 3, 3)];
[self.profileButton setBackgroundImage:buttonProfileDefault forState:UIControlStateNormal];
[self.profileButton setBackgroundImage:buttonProfileDefault
                              forState:UIControlStateSelected];
[self.profileButton setBackgroundImage:buttonProfileDefault forState:UIControlStateHighlighted];

[self.profileButton removeConstraint:self.profileButtonConstraint];

// Animate
CGRect originalFrame = self.profileButton.frame;
originalFrame.size.width = 40;
[UIView animateWithDuration:0.2f
                 animations:^{
                     self.profileButton.frame = originalFrame;
                 }
                 completion:^(BOOL finished) {
                 }];
rptwsthi
  • 10,094
  • 10
  • 68
  • 109
2

I think the problem is that your changing the background and then resizing.

The key to getting it working with auto layout is to animate the widthConstraint constant value and also set the background image in an animation.

For example, I have a button on my view name button, I have an IBOutlet to my width constraint named buttonWidth - Below is the code for my buttonPress :

UIImage *imageButton = [[UIImage imageNamed:@"button"] resizableImageWithCapInsets:UIEdgeInsetsMake(0, 10, 0, 10)];

[UIView animateWithDuration:0.01f
                 animations:^{
                     [self.button setBackgroundImage:imageButton forState:UIControlStateNormal];
                 }
                 completion:^(BOOL finished) {
                     [UIView animateWithDuration:1.0f
                                      animations:^{
                                          self.buttonWidth.constant = 300;
                                          [self.view layoutIfNeeded];
                                      }
                                      completion:^(BOOL finished) {
                                      }];


                 }];

As you can see with my code above, the key to making it work for me was setting the button background inside an animation also, for some reason if i changed the background image outside the animation it would not set it correctly until the animation completed.

Also setting the frame when using autoLayout didn't work for me, so I animated the constraint constant

Craig Mellon
  • 5,399
  • 2
  • 20
  • 25
2

Try this, instead of assigning the image as

UIImage *buttonProfileDefault = [[UIImage imageNamed:@"Profile_Button_Default"] resizableImageWithCapInsets:UIEdgeInsetsMake(3, 3, 3, 3)];

do this

UIImage *buttonProfileDefault = [UIImage imageNamed:@"Profile_Button_Default"];

no need for setting constraint of resizableImageWithCapInsets.

iDK
  • 91
  • 4
1

I had this same problem, but it happened when my app loaded up, I messed around with the button's attributes in the inspector and if you scroll down and Un-check autoresize subviews it might work, it did for me!

Nimantha
  • 6,405
  • 6
  • 28
  • 69
Bad_APPZ
  • 432
  • 1
  • 3
  • 12
  • I was so hopeful that this would fix the same issue for me, but it didn't. My background image is derived by a subclass of UIImageView, though, like this: [self setBackgroundImage:[backgroundImageView image] forState:UIControlStateNormal]; – tobinjim Nov 30 '12 at 17:13
  • @tobinjim did you try change its Style attribute from Plain to Custom? – Shinigamae Dec 05 '12 at 03:59
  • @Shinigamae I think mine was always Custom. I ultimately ditched the notion of using a subclass of UIButton and went to a UIView subclass that handles a touch. I originally like the UIButton class because title text tracks with control state; but then as I tested my program it became annoying that the title change was so sudden, so in my UIView subclass I handle the same messages but transition with a quick fade out and in of the changing text. – tobinjim Dec 06 '12 at 20:10
1

I've had a similar situation resizing subviews when using a nib. Not sure if you are or not, but what fixed my problems was unchecking 'Use Autolayout' on my various views.

Nimantha
  • 6,405
  • 6
  • 28
  • 69
Stakenborg
  • 2,890
  • 2
  • 24
  • 30
  • That would probably fix the problem, but I want to use auto layout. And if you uncheck it, it is for the whole app! – Holger Sindbaek Dec 03 '12 at 16:48
  • AutoLayout selections are applicable only to the nib where you check or uncheck it. You can have a few nibs using autolayout, and some not using autolayout in the same app – Nitin Alabur Dec 03 '12 at 17:56
1

Could you not make a copy of the image and resize it to the correct button size?

Check out IWasRobbed "s answer in this post.

He has a nice function there for you and claims to use this method for his buttons.

Community
  • 1
  • 1
AMAN77
  • 6,218
  • 9
  • 45
  • 60
  • It might be reasonable to use for button images, but I found that these methods used a lot more memory than I desired for larger images. It would show a huge spike in the Activity Monitor instrument, and I kept getting lots of memory warnings. – AlleyGator Dec 07 '12 at 23:22