- 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: Adding a Simple Direct Manipulation Interface
Your design focus moves from the UIViewController to the UIView when you work with direct manipulation. The view, or more precisely the UIResponder, forms the heart of direct manipulation development. You create touch-based interfaces by customizing methods that derive from the UIResponder class.
Recipe 1-1 centers on touches in action. This example creates a child of UIImageView called DragView and adds touch responsiveness to the class. Being an image view, it’s important to enable user interaction (that is, set setUserInteractionEnabled to YES). This property affects all the view’s children as well as the view itself. User interaction is generally enabled for most views, but UIImageView is the one exception that stumps most beginners; Apple apparently didn’t think people would generally manipulate them.
The recipe works by updating a view’s center to match the movement of an onscreen touch. When a user first touches any DragView, the object stores the start location as an offset from the view’s origin. As the user drags, the view moves along with the finger—always maintaining the same origin offset so that the movement feels natural. Movement occurs by updating the object’s center. Recipe 1-1 calculates x and y offsets and adjusts the view center by those offsets after each touch movement.
Upon being touched, the view pops to the front. That’s due to a call in the touchesBegan:withEvent: method. The code tells the superview that owns the DragView to bring that view to the front. This allows the active element to always appear foremost in the interface.
This recipe does not implement touches-ended or touches-cancelled methods. Its interests lie only in the movement of onscreen objects. When the user stops interacting with the screen, the class has no further work to do.
Recipe 1-1. Creating a Draggable View
@interface DragView : UIImageView { CGPoint startLocation; } @end @implementation DragView - (id) initWithImage: (UIImage *) anImage { if (self = [super initWithImage:anImage]) self.userInteractionEnabled = YES; return self; } - (void) touchesBegan:(NSSet*)touches withEvent:(UIEvent*)event { // Calculate and store offset, and pop view into front if needed startLocation = [[touches anyObject] locationInView:self]; [self.superview bringSubviewToFront:self]; } - (void) touchesMoved:(NSSet*)touches withEvent:(UIEvent*)event { // Calculate offset CGPoint pt = [[touches anyObject] locationInView:self]; float dx = pt.x - startLocation.x; float dy = pt.y - startLocation.y; CGPoint newcenter = CGPointMake( self.center.x + dx, self.center.y + dy); // Set new location self.center = newcenter; } @end