iOS Recipes - Matt Drance [16]
CustomSlider/Classes/CustomSliderViewController.m
customProgress.userInteractionEnabled = NO;
UIImage* sliderPoint = [UIImage imageNamed:@"sliderPoint.png"];
[customProgress setThumbImage:sliderPoint forState:UIControlStateNormal];
UIImage *leftStretch = [[UIImage imageNamed:@"leftImage.png"]
stretchableImageWithLeftCapWidth:10.0
topCapHeight:0.0];
[customProgress setMinimumTrackImage:leftStretch
forState:UIControlStateNormal];
UIImage *rightStretch = [[UIImage imageNamed:@"rightImage.png"]
stretchableImageWithLeftCapWidth:10.0
topCapHeight:0.0];
[customProgress setMaximumTrackImage:rightStretch
forState:UIControlStateNormal];
We are not creating a true UIProgressView here but instead are using a partly disabled slider to achieve the same effect and in so doing gain the ability to use the same styling technique as for the UISlider. A subtle element here is that the image we use for the thumb image is much smaller and effectively acts as an end cap for the end of the minimum track image. With the userInteractionEnabled property set to NO and no obvious draggable element present, the slider appears to be a stylized progress bar.
The demo app includes a timer, activated by the button at the top of the screen, to demonstrate how you can easily create an animated progress bar by modifying the value property of the UISlider.
Recipe 8 Shape a Custom Gesture Recognizer
Problem
Apple provides a set of basic gesture recognizers, but what if you want to go further and recognize something more complex?
Solution
Introduced by Apple with iOS 3.2, gesture recognizers provide the best solution for all your touch recognition needs. They are easy to use, and you don’t have to write any of the tedious code usually required to track the various stages of touch input. You have recognizers at your disposal for all of the basic gestures: tap, pinch, rotate, swipe, pan, and long press. But to go further and recognize something more complex, like a circle, you need to build a custom gesture recognizer.
We base our new class, PRPCircleGestureRecognizer, on the abstract class UIGestureRecognizer, but we need to include UIKit/UIGestureRecognizerSubclass.h, because this declares additional methods and properties we may need. We also need to decide whether to make our gesture recognizer discrete or continuous. A discrete recognizer triggers the delegate action only when the gesture has been fully recognized, whereas the continuous gesture triggers the delegate action for each of the touch events that it considers to be valid.
Choosing the appropriate recognizer type depends on how we want to recognize a circle. Each touch point must lie close to the circumference, allowing for a defined amount of deviation. Unfortunately, neither the center point nor the radius of the circle is defined; therefore, the position of the circumference is unknown. To solve this problem, each of the touch points must be stored until the gesture is completed so that the extreme points of the gesture can be used to calculate the diameter and, from that, establish the position of the center point and radius. A circle gesture recognizer, therefore, must be discrete, because it can validate the touch points only once the user gesture has been completed.
The base class handles all touches and makes the required callbacks to the delegate action, so we must include a call to Super in each of the delegate methods we implement. Equally important is the underlying state machine that the base class monitors to track the recognition process. For a discrete recognizer, the state property can be set to only one of these valid states: [1]
UIGestureRecognizerStatePossible
UIGestureRecognizerStateRecognized
UIGestureRecognizerStateFailed
UIGestureRecognizerStatePossible is the initial state and indicates that the recognition process is ongoing. If recognition succeeds, then the state property will