Creating a custom slider for iPhone - 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)

Related

Using stretchable images in Xcode storyboards

I'm using storyboards to layout my view controllers and I would like to use stretchable images for my buttons (so that I don't need to generate several images with different sizes).
Is this possible to do directly in storyboards without writing any code? I'm really liking the possibility to use storyboards for all graphic stuff and keep the code clean from UI stuff, but it seems like I can't get away with it here.
If it is not possible, what would you suggest otherwise?
Update for iOS 7+
iOS 7+ now supports stretchable images natively via the asset catalog. Using the asset catalog you can now specify how images are sliced and how they scale (stretch or tile). These asset catalog attributes for the image will be reflected immediately in storyboard. Great new improvement. For more info, see Apple's docs on the Asset Catalog
For deploying to iOS versions before 7:
It's a little known fact, but you can absolutely set cap insets of an image using only Interface Builder/Storyboard and the stretching properties in the attributes inspector. Thanks to Victor for the original answer.
Looking at the stretching properties in the attributes inspector of a UIImage, the X and Y values are the positions for the stretch starting point, relative to the entire width and height of the image. A value of 0.5 would mean a point in the middle of the image.
The width and height are sizes for the stretchable area relative to the image size. So, setting the width to a value of 1 / imageWidth would set the stretchable area to be 1px wide.
Most stretchable images will stretch from the middle, so using these values for X,Y, Width, & Height will usually work:
X = 0.5
Y = 0.5
Width = 1/imageWidth
Height = 1/imageHeight
Note: Unless you have a very small image you are stretching, this means that width and height properties will be very small (e.g. 0.008) and 0.0 can be used instead. So, practically speaking, 0.5, 0.5, 0.0, 0.0 will almost always work for X,Y, Width & Height.
In the small number of cases that 0.0 does not work for Width and Height this does mean you need to use a calculator to set these values in IB. However, I think that is generally preferable than having to set it programmatically as you will be able to see the resulting stretched image in IB (WYSIWYG).
Update: Some people have pointed out that although stretching images works in Storyboard using the above suggestions, stretching images on buttons is still broken, even as of iOS7. Not to worry, this is easily addressed by creating a UIButton category that takes care of setting the cap insets for control states:
#implementation UIButton (Stretchable)
/* Automatically set cap insets for the background image. This assumes that
the image is a standard slice size with a 1 px stretchable interior */
- (void)setBackgroundImageStretchableForState:(UIControlState)controlState
{
UIImage *image = [self backgroundImageForState:controlState];
if (image)
{
CGFloat capWidth = floorf(image.size.width / 2);
CGFloat capHeight = floorf(image.size.height / 2);
UIImage *capImage = [image resizableImageWithCapInsets:
UIEdgeInsetsMake(capHeight, capWidth, capHeight, capWidth)];
[self setBackgroundImage:capImage forState:controlState];
}
}
Using this category, you can set your stretchable image for your button via Storyboard and then easily ensure that it stretches properly by calling -setBackgroundImageStretchableForState: in your -viewDidLoad. Iterating through your view hierarchy makes it trivial to do this even for a large number of buttons in your view:
NSPredicate *predicate =
[NSPredicate predicateWithFormat:#"self isKindOfClass:%#",[UIButton class]];
NSArray *buttons = [self.view.subviews filteredArrayUsingPredicate:predicate];
for (UIButton *button in buttons)
[button setBackgroundImageStretchableForState:UIControlStateNormal];
While this isn't quite as good as having a UIButton subclass which does this automatically for you (subclassing UIButton isn't practical since it's a class cluster), it does give you nearly the same functionality with just a bit of boilerplate code in your viewDidLoad -- you can set all your button images in Storyboard and still get them to properly stretch.
With Xcode 6 (and iOS7+ target) you can use slicing editor when working with images assets.
Toggle slicing mode with Editor -> Show Slicing menu or press Show Slicing button when select specific image with editor (showed below).
Then you can select image for specific display scale and drag rules or edit insets values manually.
After that you can select this image in Interface Builder. For example I use it for UIButton Background Image (IB button's representation could look bad, but it should be OK when running).
My buttons look well (running iOS 7.1 simulator and iOS 8 device).
This Apple doc link could be helpful.
It's doable in XCode's 5.0 Interface Builder with the assets catalog. Create an image asset ( if you don't already have an asset catalog you can create one as follows:
File->New->File->Resources->Asset Catalog
Then Editor->New Image Set
Set the images for each Idiom & Scale
Then hit the Show Slicing button to set the slices as you wish.
Check Apple docs here: Developer Apple: Asset Catalog Help
Then all you have to do is to set the background image of the button as the requested asset.
EDIT: I've forgot to mention that it works as desired only in iOS7
Here's what I did:
I set an outlet for the button and connected it, then did this in viewDidLoad:
[self.someButton setBackgroundImage:[[self.someButton backgroundImageForState:UIControlStateNormal] resizableImageWithCapInsets:UIEdgeInsetsMake(3, 3, 4, 3)] forState:UIControlStateNormal];
This makes it so it reuses the image you set in the storyboard, so if you change it from one color to another it will work, as long as the insets dont change.
For a view that had many of these things, I did this:
for (UIView * subview in self.view.subviews) {
if ([subview isKindOfClass:[UIImageView class]] && subview.tag == 10) {
UIImageView* textFieldImageBackground = (UIImageView*)subview;
textFieldImageBackground.image = [textFieldImageBackground.image stretchableImageWithLeftCapWidth:7 topCapHeight:5];
} else if([subview isKindOfClass:[UIButton class]] && subview.tag == 11) {
UIButton * button = (UIButton*)subview;
[button setBackgroundImage:[[button backgroundImageForState:UIControlStateNormal] resizableImageWithCapInsets:UIEdgeInsetsMake(3, 3, 4, 3)] forState:UIControlStateNormal];
}
}
Note that I set the tags for all the ones I wanted stretched.
I'm in the same boat as you though, I'd love being able to set these very UI centric things on the storyboard itself.
Use the Xcode Slicing feature to specify the dimensions of a resizable center area of the image and to optionally specify end caps, which are areas of the image that should not be filled by the resizable area.
See About Asset Catalogs

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.

how to Change a Rounded Rect UIbutton background color

how to Change UIbutton background color??
I try it on IB, but it doesn't work. only changes it for custom button.
I would like to change the white color on the rounded rect button.
Or instead how to make a custom button whit rounded corners
thanks!
Rounded rect button's color can be changed to any color with the background color property in IB as well as through coding, but can not change its color to transparent color easily. For that, you better use a custom button with either rounded image or set layer as demonstrated in the example and don't forget to add Quartz Core framework in you project as well as to import it in your class.
UIBUtton *myBtn = [UIButton buttonWithType:UIbuttonTypeCustom];
myBtn.frame = frame; //your desired size
myBtn.clipsToBounds = YES;
myBtn.layer.cornerRadius = 5.0f;
[self.view addSubView:myBtn];
You may find it difficult to adjust the default button. However you can use any view you want with a custom button.
Here's an article on creating views with rounded corners:
http://iphonedevelopment.blogspot.com/2008/11/creating-transparent-uiviews-rounded.html
You also may look at a program called Opacity, which allows you to create a a lot of customized standard iOS interface art/buttons.
http://likethought.com/opacity/
UIButton *tagButton = [UIButton buttonWithType:UIButtonTypeRoundedRect];
and have a look at this... that my do the trick.. i did it for mine.
You can use a custom UIButton with custom images for backgroundimage for each state. Just make the different states of your rounded button in photoshop for example.
You can use Custom button But for that use the image of button of white rounded corners
so it will be look like white round rectangle button
You should use UIButtonTypeCustom, instead of any other.

Creating pixel perfect standard UIBarButtonItem with custom image inside

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?

iPhone ProgressBar

How can I change the color as well as size of UIProgressBar in iPhone SDK
Assuming you mean a UIProgressView, you can resize it as you would any other view, by setting the frame:
UIProgressView *progressView = [[UIProgressView alloc] initWithProgressViewStyle:UIProgressViewStyleBar];
[progressView setFrame:CGRectMake(0,0,320,10)];
or if you're using the default style, you can set the frame in the init method:
UIProgressView *progressView = [[UIProgressView alloc] initWithFrame:CGRectMake(0,0,320,10)];
As far as I know, the color of a UIProgressView cannot be changed. You'll probably have to roll your own view for that.
As Can noted, there is very little customization available for UIProgressView... pretty sucky. The solution I just implemented was to hack a UISlider. Here's the inspiration, from Apple's support forum.
Create a new UISlider
Set the setMinimumTrackImage and setMaximumTrackImage to your desired UIImage values
Set the setThumbImage to nil
Set the upper and lower bounds of the slider
Once this is setup and added to your UIView, use your custom method to set the value of the slider to the value you would normally have assigned to the UIPRogressView's progress.
You could probably also hack one together using an image that looks like the progress bar at it's smallest size and then create a stretchable image with it.
UIImage *progressBarImg= [someImage stretchableImageWithLeftCapWidth:5.0 topCapHeight:0.0];
Then you could set the image as the backgroundImage for a disabled UIButton and animate the button width incrementally to indicate progress. I haven't tried this, but I think it would work.