UIBarButtonItem with stretched not tiled UIImage in iOS5 - iphone

I am using the appearance API to customise the look of my UIBarButtonItems.
I currently need to make my buttons look like this:
In iOS5 you have this method which is what I am using:
UIImage *button = [[UIImage imageNamed:#"btn"]
resizableImageWithCapInsets:UIEdgeInsetsMake(3, 3, 3, 3)];
[[UIBarButtonItem appearance] setBackgroundImage:button forState:UIControlStateNormal
barMetrics:UIBarMetricsDefault];
But this tiles the non capped portion of the image instead of stretching which gives me this:
iOS 6 has a new method
resizableImageWithCapInsets:resizingMode:
Which lets you specify a 'stretch' resize mode but it is not available for iOS5.
How do I make the button stretch rather than tile the centre of the image for iOS5?

Turns out this is not possible in iOS5, buttons should always use a horizontal style gradient if they are styled since the image will always be tiled. I ended up changing the gradient direction.

You can use the old and deprecated stretchableImageWithLeftCapWidth:topCapHeight: method for iOS5 if you need stretching:
UIImage* (^makeStretchableImage)(UIImage*, CGSize) = nil;
if ([UIImage instancesRespondToSelector:#selector(resizableImageWithCapInsets:resizingMode:)])
{
// If resizableImageWithCapInsets:resizingMode: is available, use it
makeStretchableImage = ^(UIImage* image, CGSize inset) {
return [image resizableImageWithCapInsets:UIEdgeInsetsMake(inset.height, inset.width, inset.height, inset.width) resizingMode:UIImageResizingModeStretch];
};
}
else
{
// Else, we are on an older iOS release, use the deprecated iOS5 method instead
makeStretchableImage = ^(UIImage* image, CGSize inset) {
return [image stretchableImageWithLeftCapWidth:inset.width topCapHeight:inset.height];
};
}
UIImage* stretchableImage1 = makeStretchableImage(originalImage1, CGSizeMake(5,2));
UIImage* stretchableImage2 = makeStretchableImage(originalImage2, CGSizeMake(15,4));
UIImage* stretchableImage3 = makeStretchableImage(originalImage3, CGSizeMake(8,5));

Related

UInavigationbar background image does not resize correctly when orientation changes from landscape to portrait

I am trying to set the background image of uinavigationbar for the portrait and landscape orientations. I am using the following code:
UIImage *navbarImage = [[UIImage imageNamed:#"navbar"]
resizableImageWithCapInsets:UIEdgeInsetsMake(0, 9.0, 0, 9.0)];
UIImage *navbarLandscapeImage = [[UIImage imageNamed:#"navbar-landscape"]
resizableImageWithCapInsets:UIEdgeInsetsMake(0, 9.0, 0, 9.0)];
[[UINavigationBar appearance] setBackgroundImage:navbarImage
forBarMetrics:UIBarMetricsDefault];
[[UINavigationBar appearance] setBackgroundImage:navbarLandscapeImage
forBarMetrics:UIBarMetricsLandscapePhone];
However, in the iOS5.1 simulator, when I change the orientation from portrait to landscape to portrait, the image that is used is navbar-landscape.png instead of navbar.png.
Here are some example images:
Portrait default:
Change to Landscape:
Change back to Portrait:
Does anyone have an idea of what the problem is here? I am not sure why the wrong image is getting used.
Actually, it turns out that the problem is a bug in the simulator. I tried all of the solutions described above and none made a difference for when the problem gets resolved or not.
Where are you setting this? You could try adding it to -(void)viewWillLayoutSubviews.
You could just give one image both for landscape and potrait no need of having two different
two different images
instead of giving UIEdgeinset like this
UIImage *navbarImage = [[UIImage imageNamed:#"navbar"]
resizableImageWithCapInsets:UIEdgeInsetsMake(0, 9.0, 0, 9.0)];
you could specify the top and bottom inset so that it will adjust height wise
UIImage *navbarImage = [[UIImage imageNamed:#"navbar"]
resizableImageWithCapInsets:UIEdgeInsetsMake(some value according the image u have, 9.0, some value according the image u have, 9.0)];
In portrait mode: UINavigationBar Height = 44.
In landscape mode: UInavigationbar Height = 32
If you want them to be the same, you need to take their heights into account. For example:
- (void)viewWillAppear:(BOOL)animated {
CGRect navframe = [[self.navigationController navigationBar] frame];
navframe.size.height = 44.0f;
[self.navigationController navigationBar].frame = navframe;
}

iOS 4.3 transparent png in status bar isn't transparent

I'm having some difficulty getting the transparent bits of my png image that I'm using to replace the default status bar to be rendered as transparent in iOS 4.3. At the moment they are coming up black.
Here is the code I'm using to draw my image:
#implementation UINavigationBar (BackgroundImage)
- (void)drawRect:(CGRect)rect
{
UIImage *image = nil;
switch(self.tag)
{
case HeaderBG_Logo:
image = [UIImage imageNamed: #"top_bar_logo.png"];
break;
case HeaderBG_Plain:
image = [UIImage imageNamed: #"top_bar.png"];
break;
}
if(image != nil)
{
[image drawInRect:CGRectMake(0, 0, self.frame.size.width, self.frame.size.height)];
}
}
#end
Here is a side by side comparison of the same app running in the simulator in ios4.3 and ios5 (the image has a drop shadow as its bottom border):
As an aside, the 4.3 background image doesn't seem to be rendered as tall as the 5.0 one either.
I've tried setting the UINavigationBar to opaque / setting its background color to clearColor. None of that worked. :(
Can anyone help?
I ended up using the solution from How to create UINavigationBar drop shadow to add a shadow to the UINavigationBar instead.
Just an hint, for iOS 5 you could use the new appreance property to set the background image:
[[UINavigationBar appearance] setBackgroundImage:[UIImage imageNamed:#"top_bar.png"] forBarMetrics:UIBarMetricsDefault];
This will set the image for all UINavigationBars in the app.
I am not sure to understand if you are concerned by the status bar or by the navigationBar. According to you question it seems you are more concerned by the Navigation so here is a sample code that worked for me to add a background image for iOS5 and iOS4. It works with transparent png.
Just add this in the loadView method of your viewController:
#define kBackgroundImageTag 42
UINavigationBar *theNavigationBar = self.navigationController.navigationBar;
UIImage *myBackgroundImage = [UIImage imageNamed:#"myImage.png"];
if([theNavigationBar respondsToSelector:#selector(setBackgroundImage:forBarMetrics:)]) //iOS5 stuff
{
[theNavigationBar setBackgroundImage:myBackgroundImage forBarMetrics: UIBarMetricsDefault];
}
else if(![theNavigationBar viewWithTag:kBackgroundImageTag]) //iOS 4 stuff
{
UIImageView *imageView = [[UIImageView alloc] initWithImage:myBackgroundImage];
imageView.tag = kBackgroundImageTag;
[theNavigationBar insertSubview:imageView atIndex:0];
}
Hope it helps !

annotationView override drawRect, image with alpha

Hello i want to override drawrect in my custom annotationView, so when i write
[[_mapView viewForAnnotation:annotation] setNeedsDisplay];
my annotation view will be redrawn and i wouldn't have to remove the annotation and add it again.
here is my drawRect
- (void)drawRect:(CGRect)rect {
UIImage* theImage = nil;
if( _pinType == T_UNKNOWN ) theImage = [UIImage imageNamed:#"imgU.png"];
else theImage = [UIImage imageNamed:#"imgK.png"];
[theImage drawInRect:rect];
}
The problem is that my images are with alpha and the alpha part is black.
So maybe anyone knows the solution or some suggestions to this?
I've read a lot of post about this, also using core graphics, but didn't find the solution..
Thanks in advance!
Do you want this view to be partially transparent and display things under it? If so, use [self setOpaque:NO]. An opaque view's drawRect is responsible for drawing every pixel in the rectangle with a fully opaque color.
This function will be work correct for iOS 5.0. When you will use iOS version < 5.0, you'll got alpha part as black.
To try use another method for draw your images. I don't know for what you use this code. To try use:
UIImageView *image = [[UIImageView alloc] initWithImage: theImage];
image.opaque = NO;
[self.view addSubview: image];

NavigationBarStyle issue when switching from iOS 4 to 5

Have a little design issue after having upgraded to iOS 5 and Xcode 4.2
This is how my view looked in iOS 4:
1 http://casperslynge.dk/1
And this is how it looks like in iOS 5:
2 http://casperslynge.dk/2
In my navigation delegate I have the following method to draw the "image" at the top:
- (void)drawRect:(CGRect)rect {
UIImage *image;
if(self.barStyle == UIBarStyleDefault){
image = [UIImage imageNamed: #"topbar_base.png"];
}
else{
image = [UIImage imageNamed: #"nyhedsbar_base.png"];
}
[image drawInRect:CGRectMake(-1, -1, self.frame.size.width+3, self.frame.size.height+3)];
}
And inside my controller I set the following:
self.navigationBarStyle = UIBarStyleBlack;
How come it is not working in iOS 5?
Thanks
Under iOS5, you need to use UIAppearance. Have a look at that. Here's an example for using it conditionally so that you can continue to support iOS4:
// iOS5-only to customize the nav bar appearance
if ([[UINavigationBar class] respondsToSelector:#selector(appearance)]) {
UIImage *img = [UIImage imageNamed: #"NavBarBackground.png"];
[[UINavigationBar appearance] setBackgroundImage:img forBarMetrics:UIBarMetricsDefault];
}
As you can see, this sets a custom background image for all UINavigationBars. There are lots of things you can do with UIAppearance. You'll want to keep any custom stuff you're currently doing in drawRect: since pre-iOS4 devices will still use that and not the new UIAppearance code.

iPhone development: How to create colored or translucent background for UIActionSheet?

When you try deleting a note in iPhone's Notes application, an UIActionSheet pops up. The sheet is translucent (but not black translucent). How is that achieved? Is it possible to make the background of UIActionSheet a certain color?
I usually implement the following delegate method:
- (void)willPresentActionSheet:(UIActionSheet *)actionSheet
Just to make a sample. In this case I use a stretched png as a background:
- (void)willPresentActionSheet:(UIActionSheet *)actionSheet {
UIImage *theImage = [UIImage imageNamed:#"detail_menu_bg.png"];
theImage = [theImage stretchableImageWithLeftCapWidth:32 topCapHeight:32];
CGSize theSize = actionSheet.frame.size;
// draw the background image and replace layer content
UIGraphicsBeginImageContext(theSize);
[theImage drawInRect:CGRectMake(0, 0, theSize.width, theSize.height)];
theImage = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
[[actionSheet layer] setContents:(id)theImage.CGImage];
}
and this is the result:
alt text http://grab.by/4yF1
You can use the code below:
actionSheetObj.actionSheetStyle=UIActionSheetStyleBlackOpaque;
or
actionSheetObj.actionSheetStyle=UIActionSheetStyleBlackTranslucent;
actionSheetObj.actionSheetStyle=UIActionSheetStyleBlackTranslucent;
It's not too difficult. You can use the following code:
CGSize mySize = myActionSheet.bounds.size;
CGRect myRect = CGRectMake(0, 0, mySize.width, mySize.height);
UIImageView *redView = [[[UIImageView alloc] initWithFrame:myRect] autorelease];
[redView setBackgroundColor:[UIColor colorWithRed:1.0 green:0.0 blue:0.0 alpha:0.5]];
[myActionSheet insertSubview:redView atIndex:0];
Just make sure you present the UIActionSheet before doing this or the size wont be set. That makes it kind of ugly, but you could do something like:
[myActionSheet showInView:self.view];
if (!redAdded) {
redAdded = YES;
//THE ABOVE CODE GOES HERE
}
You can definitely adjust the opacity by setting the alpha value. Interface Builder lets you edit the value directly, but in code I think you would do:
[[myActionSheet view] setOpaque:NO];
[[myActionSheet view] setAlpha:0.5];
I'm not sure if you need the setOpaque call or not - I think that is used to help optimize performance, as the iPhone won't try to render anything hidden by the opaque view.
It looks black to me (note: using 2.2.1). The only reason there's a color to it is because of the yellow behind it.
One option would be to use the black transparent background and find out the size and speed of the action sheet. Then create a view and animate it in at the same time you show the action sheet, just underneath it, to give it a tint different than the color naturally behind the action sheet. You would have to make the color view also translucent so you could see behind that as well.
I'm not sure if you can, but you might also try adjusting the opacity of the action sheet itself as well.