Wednesday, March 9, 2011

How To Do: Slide to Unlock


This is a simple tutorial  to create "slide to unlock" feature.  As you may have guessed, we have to use UISlider. UISlider is an awesome object for many purposes - adjusting parameters of an object, or values of anything (size, amount, etc). But this time we will use it as a "Unlock Key". This type of control is useful when you have an app doing something and the user then puts the iPhone in his pocket while the app is still running. If we just use a normal UIButton to unlock, the user could accidentally touched it while the phone is in the pocket, and unlocked the screen of the app, accidentally. This is the same application as the normal iPhone lock feature.



Ok, all we need in the project is a UISlider, a UIImageView and a UILabel. In .h, we declared them as follows:

 IBOutlet UISlider *slideToUnlock;

IBOutlet UIButton *lockButton;

IBOutlet UILabel *myLabel;

IBOutlet UIImageView *Container;

The lockButton is just a control to enable you to enter the "Locked" status. Also we will be needing 3 methods to help us implementing the "Slide to Unlock" feature in our app.

 
-(IBAction)UnLockIt;

-(IBAction)LockIt;

-(IBAction)fadeLabel;

So, how do we go about implementing it. We need to think of the behaviour, of course. We want the user to slide the slider ball until the very end (right hand side), only then the screen be unlocked. Also, if the user slides half way or not until the very end, and let go (untouch) of the slider ball, we need to slide back the slider ball into initial position (value = 0, at the most left side).

Translating that behaviour into code means: Since the behaviour depends on untouch action, therefore we will use the "Touch Up Inside" delegate of the UISlider. So we will connect the "Touch Up Inside" method to the UnLockIt method.

Let's take a look inside the UnLockIt method - we need to check the value of slider (which equals to the location of the slider ball), and translate the behaviour we stated above into codes:
 
-(IBAction)UnLockIt {



if (!UNLOCKED) {



if (slideToUnlock.value ==1.0) {  // if user slide to the most right side, stop the operation 

// Put here what happens when it is unlocked



slideToUnlock.hidden = YES;

lockButton.hidden = NO;

Container.hidden = YES;

myLabel.hidden = YES;

UNLOCKED = YES;

} else { 

// user did not slide far enough, so return back to 0 position



[UIView beginAnimations: @"SlideCanceled" context: nil];

[UIView setAnimationDelegate: self];

[UIView setAnimationDuration: 0.35];

// use CurveEaseOut to create "spring" effect

[UIView setAnimationCurve: UIViewAnimationCurveEaseOut]; 

slideToUnlock.value = 0.0;



[UIView commitAnimations];



}

} 

}

You notice that we also declare a global variable of type BOOL to check the state of the lock. If the slider ball is at the most right, the value is 1.0 (this is the default max value of a UISlider, you can change in IB if you want), then execute the method to unlock it, in this example, just to hide the slider, label and so on and display the Lock button. If it is not reaching to the right side, then we use CoreAnimation to animate the auto sliding of the slider ball back to initial position of 0.0 (which is at the most left hand side).

Note that I use the UIViewAnimationCurveEaseOut, this animation curve starts out very fast immediately and then slows down at the end. This is to make it similar to a spring reaction.

You also notice we added a label in there. Now, if you see the label in your iPhone, it fades out as you slide the slider towards the right side, we can accomplish this by tying the "Value Changed" delegate of the UISlider to the method fadeLabel as below:

 -(IBAction)fadeLabel {



myLabel.alpha = 1.0 - slideToUnlock.value;



}

This is simple really. Whenever we move the slider ball from left to right, the value of the slider (that we named slideToUnlock), will increase from 0 to 1.0. But we want to change the label's alpha (opacity) from 1.0 to 0.0, therefore a simple invert is done by taking the max value of slideToUnlock and subtracting it to its current value. A better code would be to use

 
myLabel.alpha = slideToUnlock.maximumValue - slideToUnlock.value;

especially if you changed the maximum value to other than 1.0.

That's done with the behaviour of the slider. Now, what's left is just to customize the UISlider with custom slider ball. I also put a UIImageView (Container) at the back to align it nicely with the slider ball. You could also use the container image as the Slider's minimum and maximum track images.

NOTE: Just a little note, the customizing of UISlider must be done at viewDidLoad, otherwise the slider won't be made custom for some reason.

So under viewDidLoad (or if you wish you can put it under applicationDidFinishLaunching), we put the customization code of the UISlider:
 

// I set the track images to be nothing (just a clear image)

UIImage *stetchLeftTrack= [[UIImage imageNamed:@"Nothing.png"]

stretchableImageWithLeftCapWidth:30.0 topCapHeight:0.0];

UIImage *stetchRightTrack= [[UIImage imageNamed:@"Nothing.png"]

stretchableImageWithLeftCapWidth:30.0 topCapHeight:0.0];



// this code to set the slider ball image

[slideToUnlock setThumbImage: [UIImage imageNamed:@"SlideToStop.png"] forState:UIControlStateNormal];

[slideToUnlock setMinimumTrackImage:stetchLeftTrack forState:UIControlStateNormal];

[slideToUnlock setMaximumTrackImage:stetchRightTrack forState:UIControlStateNormal];

That's about it. Enjoy.