- Touches
- Recipe: Adding a Simple Direct Manipulation Interface
- Recipe: Adding Pan Gesture Recognizers
- Recipe: Using Multiple Gesture Recognizers Simultaneously
- Recipe: Constraining Movement
- Recipe: Testing Touches
- Recipe: Testing Against a Bitmap
- Recipe: Drawing Touches Onscreen
- Recipe: Smoothing Drawings
- Recipe: Using Multi-Touch Interaction
- Recipe: Detecting Circles
- Recipe: Creating a Custom Gesture Recognizer
- Recipe: Dragging from a Scroll View
- Recipe: Live Touch Feedback
- Recipe: Adding Menus to Views
- Summary
Recipe: Drawing Touches Onscreen
UIView hosts the realm of direct onscreen drawing. Its drawRect: method offers a low-level way to draw content directly, letting you create and display arbitrary elements using Quartz 2D calls. Touch plus drawing join together to build concrete, manipulatable interfaces.
Recipe 1-7 combines gestures with drawRect to introduce touch-based painting. As a user touches the screen, the TouchTrackerView class builds a Bezier path that follows the user’s finger. To paint the progress as the touch proceeds, the touchesMoved:withEvent: method calls setNeedsDisplay. This, in turn, triggers a call to drawRect:, where the view strokes the accumulated Bezier path. Figure 1-3 shows the interface with a path created in this way.
Figure 1-3. A simple painting tool for iOS requires little more than collecting touches along a path and painting that path with UIKit/Quartz 2D calls.
Although you could adapt this recipe to use gesture recognizers, there’s really no point to it. The touches are essentially meaningless, only provided to create a pleasing tracing. The basic responder methods (namely touches began, moved, and so on) are perfectly capable of handling path creation and management tasks.
This example is meant for creating continuous traces. It does not respond to any touch event without a move. If you want to expand this recipe to add a simple dot or mark, you’ll have to add that behavior yourself.
Recipe 1-7. Touch-Based Painting in a UIView
@interface TouchTrackerView : UIView { UIBezierPath *path; } @end @implementation TouchTrackerView - (void) touchesBegan:(NSSet *) touches withEvent:(UIEvent *) event { // Initialize a new path for the user gesture self.path = [UIBezierPath bezierPath]; path.lineWidth = 4.0f; UITouch *touch = [touches anyObject]; [path moveToPoint:[touch locationInView:self]]; } - (void) touchesMoved:(NSSet *) touches withEvent:(UIEvent *) event { // Add new points to the path UITouch *touch = [touches anyObject]; [self.path addLineToPoint:[touch locationInView:self]]; [self setNeedsDisplay]; } - (void) touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event { UITouch *touch = [touches anyObject]; [path addLineToPoint:[touch locationInView:self]]; [self setNeedsDisplay]; } - (void) touchesCancelled:(NSSet *)touches withEvent:(UIEvent *)event { [self touchesEnded:touches withEvent:event]; } - (void) drawRect:(CGRect)rect { // Draw the path [path stroke]; } - (id) initWithFrame:(CGRect)frame { if (self = [super initWithFrame:frame]) self.multipleTouchEnabled = NO; return self;} @end