Creating pixel perfect standard UIBarButtonItem with custom image inside - iphone

I've been scratching my head over this for the past couple of hours. Is it possible to create a standard UIBarButtonItem with a custom image inside? All I want is the standard blue button, but with an image that represents preferences (a screwdriver or cog wheel that I'll create myself) inside of it. I'd rather not use Photoshop to do this, since I'd like every single pixel to be perfect and future proof, in case Apple releases even higher resolution iOS devices.
I've found a wonderful project on GitHub that includes every graphic element shipped with iOS, and I've extracted what appears to be the image Apple itself uses when creating standard UIBarButtonItems. Problem is, it can't be resized to the proper dimensions in a way that I know of. In case it's not possible to do what I want with code, then maybe someone can tell me how to use this image.
GitHub - UIKit-Artwork-Extractor
UINavigationBarDefaultButton#2x.png
Thanks!

Just create your image, in a single color (only the alpha channel is significant) and use initWithImage:style:target:action: with the UIBarButtonItemStyleBordered or UIBarButtonItemStyleDone style.
If you want a full-color image, you'll have to use the image you linked. The secret is to resize it by duplicating the "middle" column and row of pixels in the style of an Android 9-patch image, rather than by scaling the entire thing.

Images like that are used by making them stretchable. Basically, you want only the middle of the image to be stretched when you resize the image, while the left and right cap should not be scaled, to avoid distortion.
UIImage *buttonImage = [UIImage imageNamed:#"UINavigationBarDefaultButton.png"];
UIImage *stretchableButtonImage = [buttonImage stretchableImageWithLeftCapWidth:5 topCapHeight:0];
UIButton *button = [UIButton buttonWithType:UIButtonTypeCustom];
[button setBackgroundImage:stretchableButtonImage forState:UIControlStateNormal];
In your case however, why don't you just use a UIBarButtonItem with the UIBarButtonItemStyleDone or UIBarButtonItemStyleBordered as its style?

Related

Create Custom button like human Hand

As a part of my app i need to fire a method while clicking any where inside a human hand image. Human hand image is placed in a image view. i need to add a button in-spite of adding gestures. Is it possible to create a custom button like human hand exactly show in the image below?
thanks
Create a custom UIButton add the image hand as its backgroundImage or setImage. Then use /assign this image inside. Like below:
handButton = [UIButton buttonWithType:UIButtonTypeCustom];
[handButton addTarget:self action:#selector(handImage_touch) forControlEvents:UIControlEventTouchUpInside];
[handButton setBackgroundImage:[UIImage imageNamed:#"handIMAGE.png"] forState:UIControlStateNormal];
handButton.frame = CGRectMake(x, y, width, height);
[self.view addSubview:handButton];
-(void)handImage_touch{
// do anything
}
I think at first you have to make polygon which fit to your image. And then you can use touchesBegan:withEvent: to get the coordinate of touch point and judge whether the point is inside of polygon or not.
Here is similar question like yours.
How to get particular touch Area?
I think this is a little difficult work, so maybe you would better use cocos2d library which have collision judgement function.
http://box2d.org/forum/viewtopic.php?f=9&t=7487
But also I think iOS is well constructed for handling touch, so this is beneficial effort for you.

Creating a custom slider for iPhone

I need to create a custom vertical slider for my iPhone app, simply because the UISlider is to narrow. It is going to be used as a throttle "stick" for my remote controlled helicopter.
I managed to rotate the slider in xcode with
throttleSlider.transform = CGAffineTransformMakeRotation(3*M_PI_2);
but I think this is quite ugly since the slider still appear horizontally on my storyboard. Also, I can not find anyway to make the slider wider.
How will I approach this problem?
Thank you.
in the application I am developing right now we needed a custom slider. It had to be wider (44pixels wide, the default size of a table view cell). We accomplished our goal by using stretchable images and adjusting the properties of the slider:
UIImage* sliderCenterImage = [UIImage imageNamed:#"sliderCenter.png"];
[slider setThumbImage:sliderCenterImage forState:UIControlStateNormal];
UIImage *leftStretch2 = [[UIImage imageNamed:#"sliderLeft.png"]
stretchableImageWithLeftCapWidth:5.0 topCapHeight:0.0];
slider setMinimumTrackImage:leftStretch2 forState:UIControlStateNormal];
UIImage *rightStretch = [[UIImage imageNamed:#"sliderRight.png"]
stretchableImageWithLeftCapWidth:1.0 topCapHeight:0.0];
[slider setMaximumTrackImage:rightStretch2 forState:UIControlStateNormal];
This way I got an slider that fulfills a whole cell of a tableView.
thumbImage is the image that represents the middle of the slider (the one you interact with, by default a round dot), minimumTrackImage will be the part on the left of the slider (the one that by default is blue), and maximumTrackImage is the part usually left blank on the right of the center of the slider. There are more properties of the UISlider that allow further customization. Take a look at UISlider developer reference
Hope this helps.
I've used this implementation of UICustomSwitch before, from Catamount Software's blog:
UICustomSwitch
It attempts to customize the familiar UISwitch class, but it accomplishes this by subclassing UISlider, and replacing the normal switch imagery with custom images. You could download this code, then just replace the included images with something that you draw yourself.
Because this was intended to be a switch, which only has on and off settings, you'll see that it responds to touches with this:
[self setOn:on animated:YES];
Just get rid of the code that calls setOn:animated: so that the slider doesn't force its value all the way to 0.0 or 1.0.
As an updated answer, stretchableImageWithLeftCapWidth is deprecated. It is advised to use
resizableImageWithCapInsets
For a custom slider in swift:
var thumb = UIImage(named: "slider_thumb")
musicSlider.setThumbImage(thumb, forState: UIControlState.Normal)
var left = UIImage(named: "left_slide")?.resizableImageWithCapInsets(UIEdgeInsets(top: 0.0,left: 0.0,bottom: 0.0,right: 0.0))
musicSlider.setMinimumTrackImage(left, forState: UIControlState.Normal)
var right = UIImage(named: "right_slide")?.resizableImageWithCapInsets(UIEdgeInsets(top: 0.0,left: 0.0,bottom: 0.0,right: 0.0))
musicSlider.setMaximumTrackImage(right, forState: UIControlState.Normal)
The UIEdgeInserts specify the buffer of the image that won't get resized. so left:15.0 would mean the area 15 pixels in from the left will not get resized. In my case I didn't care so it was all zero.
As a note, the images themselves are what is making the slider bar wider. My thumb image is 35 pixels in height, my left and right slider images are 20 pixels in height. All are sliced and resizable from Images.xcassets (where images should be kept)

How to create a gray overlay for a UIButton in touched state programmatically?

I would like to make a generic class that when tapped, makes the element grayish.
Facebook's app is the perfect example of what I want to achieve. All their links and images become gray when tapped.
I can only guess that they are subclassing UIButton.
I have made my button's style UIButtonTypeCustom to get rid of the rounded border. Beyond this, I don't know how to have the gray overlay because I see no such property in the documentation.
Its simple:
#define TAG_GRAYVIEW 5671263 // some random number
// add the gray overlay
UIView *grayView = [[UIView alloc] initWithFrame:button.bounds];
grayView.backgroundColor = [UIColor grayColor];
grayView.tag = TAG_GRAYVIEW;
[button addSubview:grayView];
// remove the gray overlay
UIView *grayView = [button viewWithTag:TAG_GRAYVIEW];
[grayView removeFromSuperview];
I think you need to use a semi transperant grey image PNG file. You need to then set Image of button in Highlighted state.
Also note that both the images for Normal State and Highlighted State need to have the images with titles on them.
As once we set the image to button, btn.titleLabel.text won't be displayed.
So you can have a image with transperant background and title on it for Normal state. And an grey image with title on it for Highlighted State.
Code for doing it programmatically is
[btn setImage:#"Transperant.png" forState:UIControlStateNormal];
[btn setImage:#"Grey.png" forState:UIControlStateHighlighted];
Hope this helps you.
The default UIButton masks the opaque content using a gray highlight. For example when using a transparent png, only the parts that contain non-transparent pixels will be grayed out on touch. The default UIButton highlight has no effect on subviews/sublayers, and will only work on provided images. What you see in the Facebook app is probably just a UIWebView highlight, possibly customized using css.
To create something similar using your own control (to prevent the overhead of a UIWebView) you should probably create your own UIControl subclass and highlight the content on touch using a transparent CALayer. You can even mask the CALayer to only highlight the actual contents, instead of a rectangular shape.
Also see my stackoverflow post on creating custom controls for iOS by subclassing UIControl.
Try setting the button up something like this.
*mind you I didn't create the image for this example.
Set your button type to custom, and in "State Config" select "Highlighted" from there you will want to set the image of the button to be a semi-transparent grey image. There are probably several other ways to achieve this same effect but this one should be nice and simple.

Alter a UIBarButtonItem view to be transparent programmatically

I've had trouble getting this to work, nowhere have I seen a working example on the web. Now offering bounty on this as its making me crazy. It should be easy, but that doesn't seem to be the case.
I'd like my buttons on my UINavigationBar to be semi-transparent such that they allow the background of whatever is on the UINavigationBar to show through. This effect is seen in many applications, image examples below. You can do this by setting a custom background on the item, which i think is an unacceptable solution because it requires that you prepare images beforehand, and they won't be adaptable for variable buttons etc. They will not look like Apple UI and I don't believe there is a reason to do this either, UIKit is already drawing the background for these buttons, we just need to change it. The correct solution uses the bar items and views generated by Apple's apis.
UIBarButtonItem is not a UIView subclass. When you create one and add it to a UINavigationBar, some code somewhere in the framework draws a view for it. The framework methods seem to resist anything related to allowing transparency of the bar items, such as the tintColor property.
For example, this does NOT work:
UINavigationItem *item = [[UINavigationItem alloc] init];
UIBarButtonItem *editButton = [[UIBarButtonItem alloc] initWithTitle:#"SUCKS" style:UIBarButtonItemStyleBordered target:self action:#selector(whatever:)];
editButton.tintColor = [UIColor colorWithWhite:0.4 alpha:0.3];
item.leftBarButtonItem = editButton;
Nothing I do will make UINavigationBar allow semi-transparency for its bar items. I believe at runtime we need to:
Get the image for the bar item
Mask it for transparency
Set the new image on the bar item
But I haven't been able to get the image at runtime or mask it properly. How do you do this?
Create a custom uiview and draw a semi-transparent black rectangle in it and use that view with initWithCustomView.
see
and
Failing that, you may have to use an image (png). e.g. a 1x1 black pixel png with 30% opacity.You could then initWithImage.
EDIT: I have had this second approach working using:
buttonThree = [[UIBarButtonItem alloc] initWithTitle:#" sort button " style:UIBarButtonItemStyleBordered target:self action:#selector(sortMethod)];
UIImage *thebgUIimage = [UIImage imageNamed:#"semi.png"];
[buttonThree setBackgroundImage:thebgUIimage forState:UIControlStateNormal barMetrics:UIBarMetricsDefault];
This results in a button that has a transparent background image that the navbar background image shows through. However, you would need to create an image with the rounded corners on and so need an image for each button width. Also I found this thread after trying the above
A brilliant hack is to use the UISegmentedControl with a single segment (as a button) and set its tint color. Have a look at http://charles.lescampeurs.org/2011/02/10/tint-color-uibutton-and-uibarbuttonitem. I have personally implemented this. Feel free to ask any questions.
Instead of searching for code and breaking your head, my suggestion is just to have transparent image which has just border similar to button (add shadow if necessary), create a button of custom type, add the transparent background image to it and you can text as you want. From this custom button, create your bar button item accordingly.
If you're targeting for iOS 5, you can set the background image of the button.
[_button setBackgroundImage:#"image" forState:UIControlStateNormal barMetrics:UIBarMetricsDefault];
Note that you'll need to set background images for state UIControlSateSelected and again for both control states for barMetrics: UIBarMetricsLandscape, if your application allows landscape orientation.
Note again this is an iOS 5 feature.
I believe your answer is here: http://sebastiancelis.com/2009/12/21/adding-background-image-uinavigationbar/

Half of UIButton not responding to touch events

I have a UIView - which I am using as a makeshift toolbar. It contains several UIButtons. (Six, I think) in a horizontal row.
The fifth button over will only respond to [TouchUpInside] events when I click the left half of it - whereas all the other buttons work correctly.
I have gone crazy making sure there weren't any other views overlapping it, etc - and everything seems okay.
Any idea of how to investigate further? Is there any way to see an "event inspector" to see where the touch messages may be going?
Most likely, the other half is covered by a transparent view that obstructs it. See the frames of all sibling views of the button:
for (UIView *v in myButton.superview.subviews){
NSLog(NSStringFromCGRect(v.frame);
}
And see if any of the frames above the button (the array is ordered from bottom to top) overlap with it.
If they don't, see if the whole window has any views covering the button.
The problem was as follows:
The "sixth" button was a "Info Light" type button. For some odd reason - even though the bounds of this button were clearly outside of the bounds of the offending "fifth" button - the "info light" button seems to acquire touches a bit outside it's bounding box.
When I either:
Moved the "Info Light" button further away from the "fifth" button
-or-
Changed the "Info Light" button to a regular (Round Rect) button
...the problem went away!
See the two rightmost buttons in this image:
I guess your superview bounds might be a bit too small? Try to change your superview background color to red or some vivid color and check its bounds.
Well you could try to use this technique with NSLog() to log events and get a sense of what might be happening. I'm not sure if there's a better way to log events:
Observing pinch multi-touch gestures in a UITableView
Just ran into this strange problem as well and after struggling with understanding the nature of the problem, ran across this post. Thanks for the helpful tip! I know it's an old question but this is how I was able to work around it in two ways. The first was to initially create the system info light button and simply retrieve the button image and create a custom button with that image, ignoring the initial button. The advantage to this is that you always get the latest info light graphic in case it changes in the OS. The disadvantage being that a new version of the OS might decide at some point to not make the image available in this way.
UIButton *button = [UIButton buttonWithType:UIButtonTypeInfoLight];
UIImage *img = [button imageForState:UIControlStateNormal];
button = [UIButton buttonWithType:UIButtonTypeCustom];
[button setImage:img forState:UIControlStateNormal];
button.showsTouchWhenHighlighted = YES;
[button addTarget:self action:#selector(infoSelected:) forControlEvents:UIControlEventTouchUpInside];
UIBarButtonItem *barButton = [[[UIBarButtonItem alloc] initWithCustomView:button] autorelease];
[barItems addObject:barButton]; // NSMutableArray of tab bar items
The second approach, which I decided to use, so that I knew it would be available, and also to match my splash screen art in case the OS graphic changed, was to follow the same technique and simply save the original PNG to disk and add it to the project as a custom image for the button.
// Run these four lines just once in the simulator to save the original info
// light button image to disk and then eliminate these four lines and create the
// custom button with the image added to the project. Note that it may be a 1x or
// 2x image depending on the simulator device. So run it on both to get two
// versions (changing the name of course).
UIButton *button = [UIButton buttonWithType:UIButtonTypeInfoLight];
UIImage *img = [button imageForState:UIControlStateNormal];
NSData *imgData = UIImagePNGRepresentation(img);
BOOL saved = [imgData writeToFile:#"/Users/Shared/InfoLight.png" atomically:NO];
I noticed that upon selecting the infoLight type, the button could no longer be interacted with. By checking the checkbox "User Interaction Enabled" I solved the problem.