Is there a way I can use the "Slide to Unlock" slider?
I am working on an application for which I would like to implement a sliding toggle switch to imitate the iPhone's "slide to unlock".
This would basically just be an on/off switch that would be on when slid to the right and off when slid to the left. I see a slider and a switch in IB, but not one that is both. Does this exist in the SDK? Do I have to hack this together? It seems weird to me that this wouldn't be included in the SDK. Has some kind so built something like this and opened up the source code? If anyone knows of anything, please let me know. Thanks all!
I am working on an application for which I would like to implement a sliding toggle switch to imitate the iPhone's "slide to unlock".
This would basically just be an on/off switch that would be on when slid to the right and off when slid to the left. I see a slider and a switch in IB, but not one that is both. Does this exist in the SDK? Do I have to hack this together? It seems weird to me that this wouldn't be included in the SDK. Has some kind so built something like this and opened up the source code? If anyone knows of anything, please let me know. Thanks all!
Ok, so I poked around in the UICatalog sample code for a bit and I managed to make a few changes with the help of the UISlider reference doc. It was surprisingly easy to make the visual changes and increase the CGRect used to track the thumb size. I'll obviously need to adjust these more, but it's a start. This is what I did, and the referenced files are attached. I also attached a pic of how this looks in the simulator.
Code:
- (void)create_Custom_UISlider
{
CGRect frame = CGRectMake(0.0, 0.0, 300, 52.0);
CGRect thumb = CGRectMake(0.0, 0.0, 71.0, 47.0);
customSlider = [[UISlider alloc] initWithFrame:frame];
[customSlider addTarget:self action:@selector(sliderAction:) forControlEvents:UIControlEventValueChanged];
// in case the parent view draws with a custom color or gradient, use a transparent color
customSlider.backgroundColor = [UIColor clearColor];
UIImage *stetchLeftTrack = [[UIImage imageNamed:@"customTrack.png"]
stretchableImageWithLeftCapWidth:10.0 topCapHeight:0.0];
UIImage *stetchRightTrack = [[UIImage imageNamed:@"customTrack.png"]
stretchableImageWithLeftCapWidth:10.0 topCapHeight:0.0];
[customSlider setThumbImage: [UIImage imageNamed:@"customThumb.png"] forState:UIControlStateNormal];
[customSlider setMinimumTrackImage:stetchLeftTrack forState:UIControlStateNormal];
[customSlider setMaximumTrackImage:stetchRightTrack forState:UIControlStateNormal];
[customSlider thumbRectForBounds: thumb trackRect: frame value: customSlider.value];
customSlider.minimumValue = 0.0;
customSlider.maximumValue = 100.0;
customSlider.continuous = NO;
customSlider.value = 5.0;
}
I have a noob question about using this in other apps. And I guess that is - how the heck do I do that? I was thinking I could implement changes to a slider by subclassing UISlider and overriding a few methods. This seems to be what is described in the UISlider reference, but is not what's going on here. I opened the nib file in IB and I can't even find a slider in there. It looks like there stuffing this in a table somehow, but I'm obviously way off track and hoping a more experienced developer can point me in the right direction.
It appears the create_Custom_UISlider: method is being called here:
// this cell hosts the custom UISlider control
((DisplayCell *)cell).nameLabel.text = @"Customized Slider";
((DisplayCell *)cell).view = customSlider;
Ok, so there's a "cell" (whatever that is -- maybe a cell of a table?) and it's "view" is being set to the customSlider. Although I can sort of see what's happening, I don't really understand how to copy this into another application. How do I say "hey main window, plop this sweet custom slider down when you load"??
#import "sliderSwitchViewController.h"
@implementation sliderSwitchViewController
- (void)create_Custom_UISlider
{
CGRect frame = CGRectMake(0.0, 0.0, 300, 52.0);
CGRect thumb = CGRectMake(0.0, 0.0, 71.0, 47.0);
customSlider = [[UISlider alloc] initWithFrame:frame];
[customSlider addTarget:self action:@selector(sliderAction:) forControlEvents:UIControlEventValueChanged];
// in case the parent view draws with a custom color or gradient, use a transparent color
customSlider.backgroundColor = [UIColor clearColor];
UIImage *stetchLeftTrack = [[UIImage imageNamed:@"customTrack.png"]
stretchableImageWithLeftCapWidth:10.0 topCapHeight:0.0];
UIImage *stetchRightTrack = [[UIImage imageNamed:@"customTrack.png"]
stretchableImageWithLeftCapWidth:10.0 topCapHeight:0.0];
[customSlider setThumbImage: [UIImage imageNamed:@"customThumb.png"] forState:UIControlStateNormal];
[customSlider setMinimumTrackImage:stetchLeftTrack forState:UIControlStateNormal];
[customSlider setMaximumTrackImage:stetchRightTrack forState:UIControlStateNormal];
[customSlider thumbRectForBounds: thumb trackRect: frame value: customSlider.value];
customSlider.minimumValue = 0.0;
customSlider.maximumValue = 100.0;
customSlider.continuous = NO;
customSlider.value = 5.0;
}
// Implement loadView to create a view hierarchy programmatically, without using a nib.
- (void)loadView {
[self create_Custom_UISlider];
}
I checked and I do have the correctly named images in the resources folder.
It does not work.
My expectation is that it should just place the slider on the screen.
Any thoughts?
Thanks
D
and they both exhibited the same results. When I run the app in the simulator I get a nice blank view. Seems to me like we're creating an instance of the slider in our code, but not actually adding it to the view.
This happened because I hadn't brought over the sliderAction: method. So you can just delete the line above from your code or bring this method into your .....ViewController.m file:
Code:
- (void) sliderAction: (id)sender
{
}
This will allow you to execute the code inside every time the slider is moved.
Ooooh, I was gonna keep this to myself, but since I love you guys, here's the rest of it. Note that I have reset the bounds to be 0 to 1. We're going to keep the sliderAction: method in this time.
Code:
- (void)create_Custom_UISlider
{
CGRect frame = CGRectMake(10.0, 50.0, 300, 52.0);
CGRect thumb = CGRectMake(0.0, 0.0, 71.0, 47.0);
customSlider = [[UISlider alloc] initWithFrame:frame];
[customSlider addTarget:self action:@selector(sliderAction:) forControlEvents:UIControlEventTouchUpInside];
// in case the parent view draws with a custom color or gradient, use a transparent color
customSlider.backgroundColor = [UIColor clearColor];
UIImage *stetchLeftTrack = [[UIImage imageNamed:@"customTrack.png"]
stretchableImageWithLeftCapWidth:10.0 topCapHeight:0.0];
UIImage *stetchRightTrack = [[UIImage imageNamed:@"customTrack.png"]
stretchableImageWithLeftCapWidth:10.0 topCapHeight:0.0];
[customSlider setThumbImage: [UIImage imageNamed:@"customThumb_off.png"] forState:UIControlStateNormal];
[customSlider setMinimumTrackImage:stetchLeftTrack forState:UIControlStateNormal];
[customSlider setMaximumTrackImage:stetchRightTrack forState:UIControlStateNormal];
[customSlider thumbRectForBounds: thumb trackRect: frame value: customSlider.value];
customSlider.minimumValue = 0.0;
customSlider.maximumValue = 1.0;
customSlider.continuous = YES;
customSlider.value = 0.0;
}
- (void) sliderAction: (UISlider *) sender
{
if (customSlider.value != 1.0) //if the value is not the max, slide this bad boy back to zero
{
[sender setValue: 0 animated: YES];
}
else {
//add your code here for the event you want to trigger
}
}
I hope this encourages more of you to share your code! That's what we're all here for.
Here's another tip:
You may be having a problem with your thumb overlapping the end of the slider. Well that just won't do. I was able to solve this by adding some blank space on the end of the .png file for the thumb. I couldn't figure out how to set the location of the thumb with code.
- (void) sliderAction: (UISlider *) sender
{
if (customSlider.value != 1.0) //if the value is not the max, slide this bad boy back to zero
{
[sender setValue: 0 animated: YES];
}
else {
if (customSlider.value == 1.0) //if the value is max, slide this bad boy back to zero and execute code
{
[sender setValue: 0 animated: NO];
}
// the rest of your code here.
}
}
I did this as I am having the custonSlider control my view transition. So I want the slider back at the start on the next view. So I can use it again to go back.
Looks great and you can't accidentally change views!
Great, I'm glad this is useful. Judging from the number of views, there have been a good number following along with this. I'd love to see other ways people are implementing this.
Ok, so I poked around in the UICatalog sample code for a bit and I managed to make a few changes with the help of the UISlider reference doc. It was surprisingly easy to make the visual changes and increase the CGRect used to track the thumb size. I'll obviously need to adjust these more, but it's a start. This is what I did, and the referenced files are attached. I also attached a pic of how this looks in the simulator.
Code:
- (void)create_Custom_UISlider
{
CGRect frame = CGRectMake(0.0, 0.0, 300, 52.0);
CGRect thumb = CGRectMake(0.0, 0.0, 71.0, 47.0);
customSlider = [[UISlider alloc] initWithFrame:frame];
[customSlider addTarget:self action:@selector(sliderAction:) forControlEvents:UIControlEventValueChanged];
// in case the parent view draws with a custom color or gradient, use a transparent color
customSlider.backgroundColor = [UIColor clearColor];
UIImage *stetchLeftTrack = [[UIImage imageNamed:@"customTrack.png"]
stretchableImageWithLeftCapWidth:10.0 topCapHeight:0.0];
UIImage *stetchRightTrack = [[UIImage imageNamed:@"customTrack.png"]
stretchableImageWithLeftCapWidth:10.0 topCapHeight:0.0];
[customSlider setThumbImage: [UIImage imageNamed:@"customThumb.png"] forState:UIControlStateNormal];
[customSlider setMinimumTrackImage:stetchLeftTrack forState:UIControlStateNormal];
[customSlider setMaximumTrackImage:stetchRightTrack forState:UIControlStateNormal];
[customSlider thumbRectForBounds: thumb trackRect: frame value: customSlider.value];
customSlider.minimumValue = 0.0;
customSlider.maximumValue = 100.0;
customSlider.continuous = NO;
customSlider.value = 5.0;
}
I have a noob question about using this in other apps. And I guess that is - how the heck do I do that? I was thinking I could implement changes to a slider by subclassing UISlider and overriding a few methods. This seems to be what is described in the UISlider reference, but is not what's going on here. I opened the nib file in IB and I can't even find a slider in there. It looks like there stuffing this in a table somehow, but I'm obviously way off track and hoping a more experienced developer can point me in the right direction.
It appears the create_Custom_UISlider: method is being called here:
// this cell hosts the custom UISlider control
((DisplayCell *)cell).nameLabel.text = @"Customized Slider";
((DisplayCell *)cell).view = customSlider;
Ok, so there's a "cell" (whatever that is -- maybe a cell of a table?) and it's "view" is being set to the customSlider. Although I can sort of see what's happening, I don't really understand how to copy this into another application. How do I say "hey main window, plop this sweet custom slider down when you load"??
Can someone repost the .png files for me? I love to try this out.
I was also looking for the image files without success. So I created my own, by taking a screenshot of the iPhone's "slide to unlock" screen with the slider in the middle. I used Photoshop to extract the track from the rest of the screen, and to extract the thumb from the track. I have been unable to make attachments work on this board, so I have hosted the files here:
customThumb.png is 100 x 44 pixels, including the transparent sides as suggested by gibson10ma. In the code, the declaration for "thumb" needs to be changed accordingly.
customTrack.png is 101 x 95 pixels. In the code, the leftCapWidth for "stetchLeftTrack" and "stetchRightTrack" must be changed to 50. The image will stretch to the full width of the slider set in "frame".
I added a UILabel to display "slide to cancel" text. A system font size of 24, with white color, and a clear background, looks good to me.
I noticed one strange thing about the UIControlEventTouchUpInside event: this event appears to be sent twice. I found a confirmation of this behavior, with some workarounds, here.
I still have 2 minor issues that I could use help in addressing:
The left and right edges of the track get "squished" when the thumb is at the far left or right, respectively. Is there any way to stop this from happening?
The left-to-right "shimmer" animation of the text has yet to be implemented. Can someone give me some hints on how to do that?
I have no idea if Apple will object to the use of these images in an app, since they were directly copied from an iPhone screenshot.
Thanks for the help!
Last edited by mycatsnameisbernie; 09-02-2009 at 11:26 AM.
Reason: add links to files
I still have 2 minor issues that I could use help in addressing
After spending way too much time on this, I finally have some code that I am happy with. I solved the two problems from my previous post as follows:
I added the full image of the track as a UIImageView instead of making it the UISlider's background image. This avoids the "squishing" of the edges of the track as the slider moves. It also allows the UISlider to be smaller than the track, so there is no longer a need to add transparent padding to the thumb image.
I implemented the "shimmering" text animation using the method in this post.
You can download an XCode project containing my code here.
There are 2 issues that could use improvement if anyone else wants to try...
The text animation is done using a repeating NSTimer to programatically shift the text highlighting. I would have preferred to have the iPhone's graphics engine perform the animation. I couldn't figure out how to do this with Core Animation on the iPhone. I think it could be done with CA on OS X using CALayer mask layers, but mask layers are not supported on iPhone OS. It might be possible with OpenGL, but I don't have any expertise in that area.
The text rendering code only supports Roman alphabets. In order to support Asian or other non-Roman alphabets, the text drawing code needs to be modified to use glyphs instead of characters.
Hope this helps...
Last edited by mycatsnameisbernie; 09-16-2009 at 12:39 PM.
Reason: clarification
After spending way too much time on this, I finally have some code that I am happy with. I solved the two problems from my previous post as follows:
I added the full image of the track as a UIImageView instead of making it the UISlider's background image. This avoids the "squishing" of the edges of the track as the slider moves. It also allows the UISlider to be smaller than the track, so there is no longer a need to add transparent padding to the thumb image.
I implemented the "shimmering" text animation using the method in this post.
You can download an XCode project containing my code here.
There are 2 issues that could use improvement if anyone else wants to try...
The text animation is done using a repeating NSTimer to programatically shift the text highlighting. I would have preferred to have the iPhone's graphics engine perform the animation. I couldn't figure out how to do this with Core Animation on the iPhone. I think it could be done with CA on OS X using CALayer mask layers, but mask layers are not supported on iPhone OS. It might be possible with OpenGL, but I don't have any expertise in that area.
The text rendering code only supports Roman alphabets. In order to support Asian or other non-Roman alphabets, the text drawing code needs to be modified to use glyphs instead of characters.
Hope this helps...
OMG THIS IS AMAZING!!! I just have one question, how would I re-change the code so that the slider was already on the screen, rather than bringing it up with another button?
OMG THIS IS AMAZING!!! I just have one question, how would I re-change the code so that the slider was already on the screen, rather than bringing it up with another button?
Figured it out nevermind, I also figured out how to relocate the thumb and the track anywhere on the screen!
I have my slider all set up and working, But I see that the tracks are stretching and squishing between the thumbs and the end caps. I am wondering if there is a way to set the right track (or the background track) to not stretch at all, and set the left track (the top image) to stretch between the left end cap and the thumb. The backtrack image has increments dashes in it, and the toptrack image is just a black 50% alpha image.
So I have three images
1 = thumb.png 20px X 40px
2= backtrack.png 40px X 234px
2= toptrack.png 40px X 234px
After spending way too much time on this, I finally have some code that I am happy with. I solved the two problems from my previous post as follows:
I added the full image of the track as a UIImageView instead of making it the UISlider's background image. This avoids the "squishing" of the edges of the track as the slider moves. It also allows the UISlider to be smaller than the track, so there is no longer a need to add transparent padding to the thumb image.
I implemented the "shimmering" text animation using the method in this post.
You can download an XCode project containing my code here.
There are 2 issues that could use improvement if anyone else wants to try...
The text animation is done using a repeating NSTimer to programatically shift the text highlighting. I would have preferred to have the iPhone's graphics engine perform the animation. I couldn't figure out how to do this with Core Animation on the iPhone. I think it could be done with CA on OS X using CALayer mask layers, but mask layers are not supported on iPhone OS. It might be possible with OpenGL, but I don't have any expertise in that area.
The text rendering code only supports Roman alphabets. In order to support Asian or other non-Roman alphabets, the text drawing code needs to be modified to use glyphs instead of characters.
Hope this helps...
Thanks for putting the effort in to make a working project so we can see it in action. I'm using the control in a project I'm writing and I've noticed that you have to hold the thumb image before it will start sliding.
Has anyone else noticed this? Is it just me, the standard Unlock picks up your finger movement straight away?