Stretchable image stretching part wider than 1px - iphone

I would like to create a UIButton which uses a stretchable image as Background image such as that I can easily resize the button for different labels etc.
So I created the following code which works fine:
UIImage *bgImage = [[UIImage imageNamed:#"Button-Template.png"]stretchableImageWithLeftCapWidth:2 topCapHeight:2];
UIButton *loginButton = [UIButton buttonWithType:UIButtonTypeCustom];
loginButton.frame = CGRectMake(180, 280, 112, 40);
[loginButton setBackgroundImage:bgImage forState:UIControlStateNormal];
// some more stuff
Now here is the catch: The iPhone SDK assumes that the strechable part of the image is exactly one pixel in width, which is not the case in my image as I want to create a pattern, which requires a repetition every two pixels (so 2 Pixels are one pattern unit). I have found no information in the docs whether it is possible to alter the value of the strechable part width (in my case 2 instead of 1), does anybody know how to do this or how I could achieve my goal with a workaround? Writing the stretching part on my own seems a little far fetched right now (though I might have to get back to this).
Thanks!

From iOS 5.0 on you could use resizableImageWithCapInsets:
Check UIImage Class Reference
But this method only works on iOS >= 5.0 devices, so that can be a
turn down for now.

There is no API for using 2 pixels as the stretch width. You'll have to implement this behaviour yourself in a custom view, or use an image with a specific width.

Related

iOS Background Image doesn't display properly?

I've literally piled through hundreds go searches on google :(. I can't seem to figure out what I'm doing wrong when I create an image in photoshop (960 x 600, -40 for the status bar). The image comes out to this:
When it should look like this:
(note this is not the actually size, crappy thumbnail version :P. The size is as stated above)
This is my code:
self.view.backgroundColor = [UIColor colorWithPatternImage:[UIImage imageNamed:#"MenuBkground.png"]];
Am I doing something wrong when I make the image? Is it in the code? Any ideas?
You're using colorWithPatternImage which basically means what it says. The image will repeat itself if the space is not entirely consumed by the image. If you want to have a true background image you should create the image as a subview.
UIImage* image = [UIImage imageNamed:#"MenuBKground.png"];
UIImageView* background = [[UIImageView alloc]initWithImage: image];
[self.view addSubview: background];
Another way if your using interface builder,
Drag an image view to your viewController.
Assign that as MenuBkground.png in the inspector (first drop down box)

How do I use CGRectMake to size the background

Ok So I have this code, which allows me to put a background image in:
I would love to know how to size this, so on the iPhone 4 I can get a 320x480 size but make it nice with an image of 570.855.
self.view.backgroundColor = [UIColor colorWithPatternImage:[UIImage imageNamed:#"background_stream-570x855.jpg"]];
I have tried this:
UIImageView *image = [[UIImageView alloc]
initWithImage:[UIImage imageNamed:#"background_stream-570x855.jpg"]];
[self.view sendSubviewToBack:streamBG];
image.frame = CGRectMake(0, 0, 320, 480);
Which works, however the problem is it's behind the view, so I can't see it. I could make the view clear, but it has objects on it that need to be displayed.
Any help would be most apretiated
There are multiple options to put Views at desired location.
[self.view sendSubviewToBack:streamBG]; //Sends subview to last position i.e. at the last
[self.view bringSubviewToFront:streamBG] //Brings subview to first position i.e. at the first.
[self.view insertSubview:streamBG atIndex:yourDesiredIndex];//Put at desired index.
This is not answer to your question, though it may help you to set your imageview to desired location.
Hope it helps.
To answer part of your question about sizing. You need to use 2 different images for your app if you want the full resolution of the retina display (iPhone4) You should provide a 320x480 image (i.e. myImage.png) for older iPhones and one at twice the resolution, 640x960, for the iPhone 4. Use the exact same name for the high res version but add an "#2x" to the end (i.e. myImage#2x.png). In your code all you ever have to call is the base name (i.e. myImage.png) the app will choose the correct image based on the hardware its running on. That will get you the best experience on your app.
On the other part about the background view visibility, you could make the background color clear ([UIColor clearColor]) on the view that is blocking it. That would leave the content visible in that view but the view its self would be clear. Alternatively you could just insert the background at a specific index as #Jennis has suggested instead of forcing it to the back.

Why are these UIImages so "blurry"?

In an app I'm working on, I've got a few UIImages which for some reason come out really blurry. This specifically applies to two icons I use which are fairly small (80x15 and 65x15).
(Update: added iPad Simulator output as well -- it is blurry just as the iPad output)
Top left and right are original images, bottom left and right are how they come out on the iPad. I actually got complaints about these being awfully blurry from users, so it's not just me.
The code where one of these is put in place looks like this (can show code for other one at request):
UIButton *bWeb = [[UIButton alloc] initWithFrame:
CGRectMake(attriboffset, height - 20.f, 65.f, 15.f)];
[bWeb addTarget:self action:#selector(clickWebLink:)
forControlEvents:UIControlEventTouchUpInside];
bWeb.userInteractionEnabled = YES;
[bWeb setImage:[UIImage imageNamed:#"button-weblink-65x15.png"]
forState:UIControlStateNormal];
[bWeb setImage:[UIImage imageNamed:#"button-weblink-highlighted-65x15.png"]
forState:UIControlStateHighlighted];
[self addSubview:bWeb];
[bWeb release];
The original images are (in case you think it might be a formatting issue with the actual PNG files): ,
Make sure that all numbers in UIButton's frame are rounded/truncated to integers.
What is attriboffset?
Like hoha says, if the numbers are not integers, you will end up with fractional offsets, and devices will do some blurry antialiasing to compensate for that. The numbers should not have fractions.
I think that for some reason the image is being rendered with some kind of unnecessary processing that is causing the quality loss.
Try changing the contentMode property of your UIButton to UIViewContentModeCenter. The default is UIViewContentModeStretch.
Open your images in preview and resave them.

why does initWithPatternImage loses the alpha values of the PNG

Anyone ever seen the problem of [UIColor initWithPatternImage] ignoring the alpha values of the PNG? If so, what's the best fix?
I am using a png as a background layer to my array of button objects and it contains several pre-set alpha values per pixel in the image that is to be used as a texture background. It loads fine as a pattern/texture-color, but it comes up with all key transparent area as opaque black.
It is important that I get the right alpha values so that the button images shows correctly. The button frames do not include the alpha shadows from the background as that is not the "clickable" portion of the button. Additionally, my button object's images and background images also makes use of transparency, so it really needs to have a clear background directly behind each button to let the proper true current color settings come through (lowest layer UIView will have its background color set to the current user's selected color). Setting just the single alpha value for the UIView layer containing this texture does not work for my needs either.
Any help would be appreciated. My current workaround would be to use fully-blown, repeatedly-programmed layout of several UIImageView using the png, instead of a single UIView with the pattern fill.
Here is a snippet of code, but it's pretty standard for turning a UIImage into a UIColor for use as a pattern/texture color:
UIView *selectorView = [[UIView alloc] initWithFrame:CGRectMake(0,0,320,320)];
UIColor *background = [[UIColor alloc] initWithPatternImage:[UIImage imageNamed:#"SelectorViewBackground.png"]];
selectorView.backgroundColor = background;
[mainView addSubview:selectorView]; // pattern background layer. Add UIButtons on top of this selectorView layer
[self addSubview:mainView]; // current user selected color set in mainView.
[selectorView release];
[background release];
I had the same problem with setting a background on a UIView with some transparancy,
this is how I solved it:
theView.backgroundColor = [UIColor clearColor];
theView.layer.backgroundColor = [[UIColor alloc] initWithPatternImage:[UIImage imageNamed:#"the_image_with_transparancy.png"]].CGColor;
This is probably related to:
Tiled Background Image: Can I do that easily with UIImageView?
Basically, try setting:
[view setOpaque:NO];
[[view layer] setOpaque:NO];
No I've never had an issue with this. I use code like the above all the time for apps (though often I use it in conjunction with a layer instead of a view but that shouldn't make a difference with transparency being recognized) and always have had transparency work fine.
I'd look into your PNG file. I've noticed iOS sometimes being finicky with certain PNG options/types (like an 8 bit PNG with 8 bit transparency). Make sure your PNG is saved as 24 bit with 8 bit transparency (32 bit total).
Also, stupid question, but have you verified there isn't anything black in the view/layer hierarchy behind your PNG? Sometimes it's the stupid things like that
For those who might need the work-around code where the background patterns can be laid out as rows in a UIScrollView, here it is (adjusted to remove confidentiality concerns, should work if variables properly set prior to call).
Note that there should be ways to reuse just the one allocated instance of UIImageView multiple times to either save memory or load times but time-to-market is my No. 1 driver right now. Enjoy the journey :)
UIImageView *selectorView;
for (int i = 0; i < numRows; ++i) {
selectorView = [[UIImageView alloc] initWithImage:[UIImage imageNamed:#"SelectorViewBackground.png"]];
selectorView.frame = CGRectMake(0, i * patternHeight, patternWidth, patternHeight);
[mainView addSubview:selectorView];
[selectorView release];
}

Resize image in UITableViewCell to not be total height

Current I am trying to show a simple table in my iPhone application where I use UITableViewCell's with the style UITableViewCellStyleValue1 (image to the left, detail-label right-alligned). The cells all have the default height (50.0f). Before I add an image to the cell, I resize the image to be 40x40, so that it is not the total height of the cell (I think that looks ugly).
I do this with this code:
cell.imageView.image = [UIImage imageNamed:#"icon.png"];
cell.imageView.image = [RootViewController imageWithImage:cell.imageView.image scaledToSize:CGSizeMake(40, 40)];
This is all very nice and works flawlessly. But I want to accomplish this also on the iPhone 4 (with the higher resolution screen). The problem is, that everything is scaled without problems on the iPhone 4 but the images appear very pixelated.
The reason for this is ofcourse that everything on the screen is blown up to scale to the new resolution, also the images, so the images should probably be something like 80x80. But when I resize them to 80x80 (originals are 120x120) they appear way to big, because of the scaling thing.
Is there a way to actually make my images not the complete height of a tablecell, but I want them in the higher resolution on the iPhone 4. Should I create a complete new View for this?
Oops, after the first reply I realised that my own written function was missing:
+ (UIImage*)imageWithImage:(UIImage*)image scaledToSize:(CGSize)newSize
{
UIGraphicsBeginImageContextWithOptions(newSize, NO, [[UIScreen mainScreen] scale]);
[image drawInRect:CGRectMake(0,0,newSize.width,newSize.height)];
UIImage* newImage = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
return newImage;
}
As you can see, after the first reply, I tried to get this to work with the method UIGraphicsBeginImageContextWithOptions but somehow this results in an empty image.
I assume you wrote "imageWithImage:scaledToSize:", right?
I further assume you use "UIGraphicsBeginImageContext(yourSize)" within this call. Replace that with "UIGraphicsBeginImageContextWithOptions(yourSize, NO, 2.0)" in case your platform is iPhone 4.
The "2.0" defines the scale factor for points (you define the size in points not in pixels). On pre-retina-display a point is 1x1 pixel. On retina display a point is 2x2 pixels.
Edit:
Make sure you have a high-res version of "icon.png" in your resources called "icon#2x.png". This is automatically loaded in case it is a retina display.