I wanted to understand how resizableImageWithCapInsets works so I found this image
The size of the image is 57x51 so I created the image like this
image = [[UIImage imageWithContentsOfFile:[[NSBundle mainBundle]
pathForResource:#"PopoverViewBlackBackgroundArrowDown" ofType:#"png"]]
resizableImageWithCapInsets:UIEdgeInsetsMake(25.0, 28.0, 25.0, 28.0)];
and the image view like this
UIImageView *backgroundImageView = [[UIImageView alloc] initWithImage:image];
backgroundImageView.frame = CGRectMake(0.0f, 0.0f, 210.0f, 110.0f);
[self.view addSubview:backgroundImageView];
But here's the result
It not looking like the traditional UIPopoverController. The arrow is getting resized too.
Do you have any idea why ?
Thanks for your answers.
I think your issue is that the edge insets are set incorrectly. What you should try to do is move the left and right insets to sit out side of the arrow area.
At the moment you have given the stretchable area a width of 0, in the center of the image, so it is stretching the arrow in the middle at a single point. The top and bottom insets look okay so what you'll be aiming for is something like this:
resizableImageWithCapInsets:UIEdgeInsetsMake(25.0, 10.0, 25.0, 47.0)];
That is, a 10 px margin on the left and right of the image.
Hope that helps
Related
I'm writing code to use a custom image as the background for a UIView.
The app runs in portrait only. Prior to the 4" retina screen, I used fixed size, hand-drawn png as the background image (card.png below). I had code like this:
UIView* frontView = [[UIView alloc] initWithFrame:CGRectMake(0, 0, self.bounds.size.width, self.bounds.size.height)];
frontView.autoresizingMask = UIViewAutoresizingFlexibleWidth|UIViewAutoresizingFlexibleHeight;
UIImage* cardImage = [UIImage imageNamed:#"card.png"];
UIImageView* im = [[UIImageView alloc] initWithImage:cardImage];
im.autoresizingMask = UIViewAutoresizingFlexibleLeftMargin | UIViewAutoresizingFlexibleRightMargin | UIViewAutoresizingFlexibleBottomMargin;
[frontView addSubview:im];
// frontView has a bunch of stuff added...
As you'd expect, when I run this on an iPhone 5, everything can be dynamically sized and positioned, except for the hand drawn png, card.png. So that background image isn't using the full height that is available...
So what (I think) I want to do, is something like this...
UIImage* cardImage = [[UIImage imageNamed:#"card_resizable.png"] resizableImageWithCapInsets:UIEdgeInsetsMake(72, 0, 60, 0)];
I've redrawn card.png as card_resizable.png - it's 140 pixels in height, there's an 8 pixel chunk in the middle, which I want to tile, so the top inset is 72 pixels tall and the bottom inset is 60 pixels tall.
What's the next step?
Should I create the UIImageView with the dynamic size of frontView?
How do I make the resizable image, resize?
The few things that I've tried... none of them have resulted in tiling the resizable image.
Cheers,
Gavin
Update:
I was incorrectly setting the pixel values for UIEdgeInsetsMake(72, 0, 60, 0)
These values are based on the #2x image. When changed to UIEdgeInsetsMake(36, 0, 30, 0) - I get the correct, vertical resizing.
As Mike pointed out, I needed to set the size of the UIImageView to the parent, and correctly set it's autoresizingMask:
im.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight;
I know have the UIImageView sized dynamically sized, correctly, to fill its parent view - frontView (I've given it a green background to check visually on both 3.5" screen and 4" screen.
The resizable image, cardImage, is also resizing, correctly, in the vertical plane.
Once you've passed the stretchable image to a UIImageView you just resize that image view to whatever height you need.
In your case, you probably want to make the image view fill its parent by doing this:
im.frame = frontView.bounds;
im.autoresizingMask =
UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight;
[frontView addSubview:im];
We make im fill the frontView and tell it to automatically increase its width/height when its parent (frontView) changes size. This should do what you want.
Can you try with stretchableImage
UIImage *image = [UIImage imageNamed:#"card_resizable.png"];
UIImage* cardImage = [image stretchableImageWithLeftCapWidth:0.0f
topCapHeight:70.0f];
Take a look at UIView contentMode property. it should give you some sense about how the UIImageView render the image inside, whenever it change it's size.
I have created a singup button as follows:
signupButton = [[UIButton alloc] initWithFrame:CGRectMake(10,(facebookLoginButton.bounds.size.height + 40),300,50)];
signupButton.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleTopMargin;
UIImage *signupButtonImage = [[UIImage imageNamed:#"Signup"]
resizableImageWithCapInsets:UIEdgeInsetsMake(0, 10, 0, 10)];
[signupButton setBackgroundImage:signupButtonImage forState:UIControlStateNormal];
The frame for the button is 300x50 per the above. I have created an image (for Retina devices) as 22(w)x100(h)px.
The image is 22 pixels which includes 10px rounded corners and 2px which are for the repeatable middle section.
I have tried to implement the stretch per the above code with insets as 0,10,0,10 but this does not stretch as expected.
Can someone explain what the insets should be? Also how to work these out, I cannot find any useful information on how to actually calculate what the insets should be? I have read the Apple documentation on this, but I do not understand how to work these out.
Your image has size 22x100 but it is a retina image.
That means the point size is 11x50.
The insets should be UIEdgeInsetsMake(5.0f, 5.0f, 5.0f, 5.0f)
Create stretchable Image using following code and assign it to respective UIImageView
UIImage *bgImage = [[UIImage imageNamed:#"Signup"] stretchableImageWithLeftCapWidth:10 topCapHeight:10];
you need to calculate TopCap and LeftCap of your 9 patch image properly.
Good luck.
The content stretch property is deprecated in iOS 6.0, and I can not find an alternative that seems to work right.
Here is the code that works but deprecated in iOS 6.0:
UIImageView *sectionsSeparator = [[UIImageView alloc] initWithFrame:CGRectMake(x, 0, separatorWidth, totalHeight)];
sectionsSeparator.image = [self imageForSectionsSeparator];
sectionsSeparator.contentStretch = CGRectMake(0, 0.25f, 1, 0.5f);
[self addSubview:sectionsSeparator];
I tried the code below, but the images do not line up correctly:
UIImageView* sectionsSeparator = [[UIImageView alloc] initWithFrame:CGRectMake(x, 0, separatorWidth, totalHeight)];
[sectionsSeparator setImage:[[self imageForSectionsSeparator] resizableImageWithCapInsets:UIEdgeInsetsMake(0.0f, 0.25f, 1.0f, 0.5f)]];
[overlayView addSubview:sectionsSeparator];
Maybe i'm missing something, any suggestions?
Being deprecated doesn't meant it stopped working, it just means that you should prefer an alternative but the old way is still valid.
Anyways, if you want to avoid the deprecated thing, you can create an stretchable image as it is specified in the documentation:
http://developer.apple.com/library/ios/#documentation/UIKit/Reference/UIView_Class/DeprecationAppendix/AppendixADeprecatedAPI.html
Edit:
The cap inset method is the opposite of the content stretch one (it works backwards). On the content stretch you cover with a rect what you want to be stretched, here is an example:
http://j0ris.tumblr.com/post/7345178587/uiview-contentstretch
However on the resizableImageWithCapInsets you cover what you DON'T want stretched.
During scaling or resizing of the image, areas covered by a cap are
not scaled or resized. Instead, the pixel area not covered by the cap
in each direction is tiled, left-to-right and top-to-bottom, to resize
the image.
http://developer.apple.com/library/ios/#documentation/UIKit/Reference/UIImage_Class/Reference/Reference.html#//apple_ref/occ/instm/UIImage/resizableImageWithCapInsets:
So you the insets should be made differently.
In reference to: iPhone stretchableImageWithLeftCapWidth only makes "D"s
I have an image of a button of size 13x30. I want to stretch the image to fill the button which will be of size 45x30.
Here is the code I am using:
UIImage *shareImage = [[UIImage imageNamed:#"btn_red"] stretchableImageWithLeftCapWidth:16.0f topCapHeight:0.0];
UIButton *shareButton = [[UIButton alloc] initWithFrame:CGRectMake(0, 0, 46.0f, 30.0f)];
etc....
The image I get is quite off. I am getting the image in its real size, with some sort of a lighter shadow behind it as shown in the image .
Why is this happening? I don't understand at all. I have the stretchable logic correct and I've followed what everyone is saying in tutorials/posts.
If I get some assistance I would greatly appreciate it.
I think your left cap width is wrong? If your first image is only 13 pixels wide, how can the left cap be 16?
The left cap is the width on the original image that stays unstretched
To follow up on Paul's answer,
You want to make sure that you leave some space for stretching, so zoom in using Photoshop or something similar and decide what left pixels are absolutely required.
See this: http://idevrecipes.com/2010/12/08/stretchable-images-and-buttons/
LeftCapWidth should be 6.5;
UIImage *shareImage = [[UIImage imageNamed:#"btn_red"] stretchableImageWithLeftCapWidth:6.5 topCapHeight:0.0];
UIButton *shareButton = [[UIButton alloc] initWithFrame:CGRectMake(0, 0, 46.0f, 30.0f)];
I'm implementing a drop down for iPhone. The image looks like this:
[5px corners][1 px stretchable area][10px arrow with corners]
I'd like to use something like:
UIButton *dd = [[UIButton alloc] initWithFrame:CGRectMake(0, 0, 200, 20)];
dd.autoresizingMask=UIViewAutoresizingFlexibleWidth;
[dd setBackgroundImage:[[UIImage imageNamed:#"dd"] stretchableImageWithLeftCapWidth:5 topCapHeight:0] forState:UIControlStateNormal];
I can't seem to find a way to specify the rightcapwidth. The docs say it is calculated from the leftcapwidth. There must be a way to have a stretchable image with different left and right fixed sizes? Draw 9-patch image maybe?
Anyone have a solution for this on iphone?
The next pixel after the leftcap is the only thing that is stretched horizontally. Therefore the 10 pixels on the right are preserved with their original size, and there is no point in having a right cap.
If there is any distortion on your image is due to something else. This should work:
UIButton *dd = [UIButton buttonWithType:UIButtonTypeCustom];
[dd setFrame:CGRectMake(0, 0, 200, 20)];
[dd setBackgroundImage:[[UIImage imageNamed:#"dd.png"] stretchableImageWithLeftCapWidth:5.0 topCapHeight:0.0] forState:UIControlStateNormal];
[self.view addSubview:dd];
The reason why you would still see distortion is because the original image is wider than the width that you are specifying (or height if the distortion is vertical). E.g. if you want a button with a width of 200px but the original image is 300px wide you will see distortion even while using it as a stretchable image. Start off with a short image which can be stretched to whatever size you wish with the specified cap inserts e.g. an image with a width of 10px would work for your needs.