UIButton backgroundImage stretchableImageWithLeftCapWidth:topCapHeight issue - iphone

I have a UIButton with a specified width of 200. Its autoresizingMask property is set to UIViewAutoresizingFlexibleWidth. A UIImage is applied to this button's backgroundImage property. This UIimage is defined as follows:
[[UIImage imageNamed:#"buttonimage.png"] stretchableImageWithLeftCapWidth:10 topCapHeight:0]
buttonimage.png has a width of 400px (2x width of button, because of retina resolution) and represents a rounded rectangle. In portrait mode, everything is fine. As soon as the user rotates the device and the iPhone enters landscape mode, the UIButton is stretched. Due to this behaviour, the left rounded border of the image stays the same (stretchableImageWithLeftCapWidth:) but the right corners are also stretched. Is there any property I forgot to set that ensures only one specified pixel (e.g. the tenth one) is stretched and anything else retains it dimensions?
Thanks in advance!
Edit: If I use a smaller image, that is already stretched in portrait mode, both borders seem to be expanded.
Solved!
If your image is called "myImage.png" and it is the retina version, just call it "myImage#2x.png"

Is there any property I forgot to set
that ensures only one specified pixel
(e.g. the tenth one) is stretched and
anything else retains it dimensions?
Not really, but given the size of your images, you should re-read the leftCapWidth property.
The way stretchable images work is: you provide the left cap, the next pixel is stretched, and the right side of the image with width = (total width - left cap + 1) stays the same. Given that you are setting left cap to 10, and the original image is 400, you are telling iOS that the right non stretchable right side of your image is 400-10-1=389px. The same thing applies vertically. Check if you are using #2x images on a normal device without a #2x on its name, or if the 2x versions don't have exactly twice the pixels, or there is an uppercase/lowercase difference. You can find this out nslogging the size of the image loaded.
I don't know why the right side of your image is stretched. Given that you have height=0, the whole image can be stretched vertically if the button height changes, but it's unlikely that this causes a distortion of only the right side.

There is nothing wrong with your code as far as I can tell, that should be causing the right side of the image to be cropped. Below is the exact code I use, which I know works, to produce the same effect you're looking for.
UIButton *button=[[UIButton alloc] initWithFrame:CGRectMake(0, 0, 245, 51)];
button.autoresizingMask=UIViewAutoresizingFlexibleWidth;
[button setBackgroundImage:[[UIImage imageNamed:#"userbubble.png"] stretchableImageWithLeftCapWidth:40 topCapHeight:0] forState:UIControlStateNormal];
[self.view addSubview:button];
My guess is that the problem is coming from the png you're using, or possibly from the Compress PNG Files setting in your project. Also, since the image you are using is so big, try putting the left cap out further, say 40 or 50 pixels in.

Related

iOS background and images seem to not scale properly for retina display

When using the following code:
self.view.backgroundColor = [[UIColor alloc] initWithPatternImage:[UIImage imageNamed:#"texture1.png"]];
The texture background of my view gets set just fine. But I can see that the images are not scaled properly for a retina display, they seem more pixelated, rather than rich in texture and color as they should be. I have had this issue with other images too, when trying to make an image the size of the iphone 5 screen fade away, only a part of it would be seen, and the rest would be cut off, even though the resolution is fine. Any idea what I am missing here?
EDIT: Does it have to do with the default dpi of the images that I am using?
EDIT #2: Here is a screenshot:
On a side note, does anyone know if good background texture sources besides http://subtlepatterns.com/?
EDIT #3: Here is a good example of me attempting to use the ios-linen pattern
firstly remove .png from image name if you are use #2x image
self.view.backgroundColor = [[UIColor alloc] initWithPatternImage:[UIImage imageNamed:#"texture1"]];
Please check the image height and width for retain display ..
By Apple On devices with high-resolution screens, the imageNamed:, imageWithContentsOfFile:, and initWithContentsOfFile: methods automatically looks for a version of the requested image with the #2x modifier in its name. If it finds one, it loads that image instead. If you do not provide a high-resolution version of a given image, the image object still loads a standard-resolution image (if one exists) and scales it during drawing.
Instead of using initWithPatternImage you should add a UIImageView to the UIView . This is better because :-
The UIImageView will contain the image according to its specific width and height.
Also, the initWithPatternImage method consumes MORE MEMORY than the UIImageView.
I would prefer to use a UIImageView rather than the
initWithPatternImage:[UIImage imageNamed:#"texture1.png"]
If the image is still not clear you can add the #2x image to the UIImageView and you will see the clarity is more.

Exporting a hi-res image from a UIView that contains other views

I am trying to export an image from a UIView that contains a UIImage view and some labels. I am not sure I am going about this the right way. I want to export everything in the view and maintain the layout. I want to export at 1536 x 2048.
I am using the following code with renderInContext to grab an image of the main view (UIView). Kind of works, but the layout gets messed up, basically the layout changes and the labels do not scale properly. Is renderInContext the right way to go for something like this? Is there a better way?
you can download the whole project here: http://tinyurl.com/7qvhqtp
UIGraphicsBeginImageContext(CGSizeMake(1536, 2048));
viewOutput.frame = CGRectMake(0, 0, 1536, 2048);
[[viewOutput layer] renderInContext:UIGraphicsGetCurrentContext()];
UIImage *image = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
UIImageWriteToSavedPhotosAlbum(image,nil,nil,nil);
This is the code I use to save the current UIView as an image. The layout gets saved perfectly.
UIGraphicsBeginImageContextWithOptions(self.view.bounds.size, self.view.opaque, 0.0);
[self.view.layer renderInContext:UIGraphicsGetCurrentContext()];
UIImage * img = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
I'm not 100% sure, but there might be some issues with UIGraphicsBeginImageContext vs UIGraphicsBeginImageContextWithOptions.
On the other hand the problem might be in your view's subview's autoresizing mask if your view has the autoresizesSubviews set to YES. I'd try to disable it if you do not have the support for rotations or at least before changing your view's frame.
The only thing you did to get a bigger image was to change the frame but the labels did not have the correct autoresize masks nor did their font size change. You can clearly see this in the "after running code" image that the label did neither move nor change size.
First, If you wan the label to change its frame when the superview's frame changes (are the labels subviews of the image? If not you may need to calculate their new frames yourself) then you should give it a suitable auroresizing mask. In your case you would want it to have a fixed distance to the bottom of the screen and a flexible distance to the top. You would also want the distances to the left and right to be fixed so that the width can be flexible.
This only leaves you with the font size problem. You should calculate the scale factor (how many times bigger everything gets) and multiply the current font size with that scale factor.

stretching images in cell.background view

I'm trying to make cell background stretch properly when in landscape mode. I' written this code:
UIImage* cellBackGroundImage = [UIImage imageNamed:#"button_listing_default.png"];
cellBackGroundImage = [cellBackGroundImage stretchableImageWithLeftCapWidth:290 topCapHeight:76];
deselectedBackground = [[UIImageView alloc] initWithImage:cellBackGroundImage] ;
[deselectedBackground setContentMode:UIViewContentModeScaleToFill];
cell.backgroundView = deselectedBackground;
The image size is 580x152. The cell size is 280x76.
But when I turn my device into landscape the rounded corners of my image is scaled but they shouldn't.
Portrait appearance: Portrait appearance http://xmages.net/storage/10/1/0/6/6/upload/456703d5.png
Landscape appearance: Landscape appearance http://xmages.net/storage/10/1/0/d/0/upload/a99fb3a8.png
The image itself: The image itself http://xmages.net/storage/10/1/0/6/6/upload/e1895d8e.png
Probably your cap values are wrong?
cellBackGroundImage = [cellBackGroundImage stretchableImageWithLeftCapWidth:290 topCapHeight:76];
Why are they so big? Do your rounded corners have such a big radius? If they are only like 10px, than use stretchableImageWithLeftCapWidth: 10 topCapHeight: 10. These values define, which portion of the image won't be scaled.
Could you perhaps show us your image?
I have found what had caused my problems. Actually it is the image itself. Stretching and auto-sizing works properly when image is smaller than the result, but if it should be wider and lower (as it was in my case) it doesn't.
So to solve my issue I, just, had to use smaller image.

How to make an custom button with an self-stretching image?

I slightly remember that there is an class which is capable of stretching an image in such a way, that the first x pixels and the last y pixels won't get stretched.
For example if you have an button image with round corners, you would want those round corners to stay intact while the middle part of that image gets stretched.
This is a feature of class UIImage itself.
- (UIImage *)stretchableImageWithLeftCapWidth:(NSInteger)leftCapWidth topCapHeight:(NSInteger)topCapHeight
You can assign the resulting image to the appropriate property of UIButton as required.

iPhone - Center UIImage in UIImageView

I have a UIImageView. I get a UIImage from a URL. The image displays in the UIImageView, but I can't get it to center correctly. The UIImage is 80 x 68 pixels. The UIImaveView's size is 90 x 90. When I display the UIImage in the UIImageView the UIImage is shrunken so that it fits, although it is already smaller than the UIImageView. I have tried all the Content Modes in IB. Some of them shift the image up so that it is no longer in the UIImageView. None of this really makes sense to me. It seems that the UIImage should display inside the UIImageView fine if it is already within the required size. Any help would be great.
With Mode of Center on the UIImageView
alt text http://img406.imageshack.us/img406/3696/screenshot20090915at447.png
With Mode of Aspect Fit on the UIImageView
alt text http://img406.imageshack.us/img406/9373/screenshot20090915at447e.png
With Center, the size of the image seems correct but you can see that it goes out of the UIImageView which has a red UIView underneath it and is actually 2px on each side larger than the image view. But with the Aspect Fit, it makes the image smaller so that it fits inside. But I don't understand why it would make it smaller if it is already small enough to fit.
Sorry for wasting anyone's time. Turns out I didn't try all of the content modes. Seems that Content Mode of Bottom top works. This is backwards from how I understood it. Thanks for all your help.
Try this. Change your UIImageView to be the same size as the UIImage that you are going to load, then position the UIImageView so that it's centered. This is the approach I've taken since I find UIImageView to be a bit funny to work with. Or, if you prefer, skip the UIImageView and just draw the UIImage using it's - (void)drawInRect:(CGRect)rect method.
Sounds like your image contains transparent areas, at least at the bottom, which shift the image off center.
Edit: Also, you should check that the resolution of the image is set to 72dpi.