TJ Asher
TJ Asher

Reputation: 767

iOS Stretchable image on UIButton showing wonky corners

OK folks,

I've searched all over and cannot seem to find a solution to my issue.

I am trying to use a sizeable image for a button background to get a custom look for a UIButton and to reduce the overall size of the app and because it seems like the right thing to do.

However, when I try to set the image on the button the button gets all weird looking and the corners do not match the standard corner radius of a regular UIButton.

I have tried creating several different sizes of images but nothing I do seems to work.

I know the caps are supposed to be even and I have that plus the 1 pixel middle to stretch.

My UIButton is 44 high. If I create an image that is 44 pixels high and 21 pixels wide and has the same rounded corner radius as the default button (it likes an aspirin caplet) and set my background image like this:

UIImage *btnImage = [UIImage imageNamed:@"buttontest1.png"];
UIImage *newImg = [btnImage stretchableImageWithLeftCapWidth:10 topCapHeight:0];

the corners just don't match and look weirdly widely stretched AND the button grows in height!

I know the stretchableImagewithLeftCapWidth is deprecated but the usage of resizableCapWithInsets makes even less sense to me and when I try to do that the button image just seems to repeat over and over.

Can anyone figure out what I'm doing wrong? Is there anyplace that explains this crap simply? I just cannot seem to get it.

Thanks! -TJ

EDIT - adding images after using the resizableImageCapWithInserts to show results. They can't be typical as I see examples all over that supposedly work but the examples never work for me. I just figured out how to add images here so maybe this helps some.

My PNG file 21pxels wide by 29 pixels tall Here is the PNG file 21px wide by 39px tall

Results of my code This is the result of using the following code to set the background image:

[self.button1 setBackgroundImage:[[UIImage imageNamed:@"buttontest4.png"] resizableImageWithCapInsets:UIEdgeInsetsMake(0, 10, 0, 10)] forState:UIControlStateNormal];

As I understand it this should copy the left 10 pixels and right 10 pixels of my 21 pixel wide image as is and stretch the middle 1 pixel across, which it appears to do but it is also making my button get larger vertically and I'm getting this weird repeat. It should be the same size as the BTN next to it.

Here is my Xcode layout: Xcode layout

No matter what image I use I see similar results.

I'm obviously not groking something here.

I appreciate the answers so far. It's becoming slightly less foggy.

TJ

EDIT2: showing samples using the cap insets method with image 21px by 44px.

All 4 buttons are 44px high when designed in storyboard.

both buttons 44px high As you can see the orange buttons are both larger than the white buttons for scale comparison.

The top button is button1, bottom is button2.

I found a way to get it closer by using the optional resizingMode parameter of UIImageResizingModeStretch.

However, notice the buttons are larger than what they should be.

Here is the code for setting the button images.

- (void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.

[self.button1 setBackgroundImage:[[UIImage imageNamed:@"buttontest1a.png"] resizableImageWithCapInsets:UIEdgeInsetsMake(10, 10, 10, 10)] forState:UIControlStateNormal];

[self.button2 setBackgroundImage:[[UIImage imageNamed:@"buttontest1a.png"] resizableImageWithCapInsets:UIEdgeInsetsMake(0, 10, 0, 10) resizingMode:UIImageResizingModeStretch]  forState:UIControlStateNormal];
}

Doing the top image with (10,10,10,10) gets me an image that does not repeat the top part of the image like previously. I know the top image is not using the optional resize parameter as this is a test to see what each gets me.

Now, to complicate things even more. If I set my top button size to 43, that is one pixel smaller than my image and make a call with the optional resize parameter I get nearly perfect results except my button is not the right size.

What the heck is going on here?

I appreciate everyone who is trying to pound some knowledge through my thick skull. TJ

buttons 43 and 44

Upvotes: 4

Views: 6930

Answers (3)

Jonny
Jonny

Reputation: 16318

The 2016 way is to do what we are told in WWDC2016 video 213 around this point: https://developer.apple.com/videos/play/wwdc2016-213/?time=1084 We can stretch assets. Sorry for just a link this time; I'll provide more details later. The instructions in the video is a minute or two at most. In short, we use the Asset Slicer tool of Xcode to define what parts of an image should not get stretched when an image is used as background of a UIButton. The UIButton can expand to any size without distorting roundd edges etc.

Upvotes: 0

borrrden
borrrden

Reputation: 33421

UIEdgeInsets is a little difficult to wrap your head around, but it is the more modern usage. I will explain the way it works. Basically, using four offsets, you are dividing your image into 9 slices. If you want to see an image of what this potentially looks like, have a look at the "Scaleable area" section of this page (Note, it is for Android, but the concept is the same. Android was just doing it first). You will notice four lines going through the image. These will correspond to your four insets. So your nine sections, from left-to-right and top-to-bottom will be:

  1. X: 0 -> Left Inset, Y: 0 -> Top Inset
  2. X: Left Inset -> (Width - Right Inset), Y: 0 -> Top Inset
  3. X: (Width - Right Inset) -> Width, Y: 0 -> Top Inset
  4. X: 0 -> Left Inset, Y: Top Inset -> (Height - Bottom Inset)
  5. X: Left Inset -> (Width - Right Inset), Y: Top Inset -> (Height - Bottom Inset)
  6. X: (Width - Right Inset) -> Width, Y: Top Inset -> (Height - Bottom Inset)
  7. X: 0 -> Left Inset, Y: (Height - Bottom Inset) -> Height
  8. Left Inset -> (Width - Right Inset), Y: (Height - Bottom Inset) -> Height
  9. X: (Width - Right Inset) -> Width, Y: (Height - Bottom Inset) -> Height

Sections 1, 3, 7, and 9 are set and will not stretch.
Sections 2 and 8 will stretch horizontally only
Sections 4 and 6 will stretch vertically only
Section 5 will stretch in both directions.

New in iOS 6, you can select a mode. You can either stretch the stretchable tiles, or repeat them to get the effect that you want (colors, etc should stretch while textures should repeat).

Upvotes: 7

endy
endy

Reputation: 3872

Try UIEdgeInsets

[button setBackgroundImage:[[UIImage imageNamed:@"buttontest1.png"] resizableImageWithCapInsets:UIEdgeInsetsMake(10, 10, 10, 10)] forState:UIControlStateNormal];

Upvotes: 5

Related Questions