Mobile

Handling Touch Input on iOS6

By Erica Sadun, January 13, 2013

Learn how to use the essential components of all touch-based interaction.

Figure 1 shows a sample interface. The subviews (flowers) are constrained into the black rectangle in the center of the interface and cannot be dragged off-view. Recipe 4's code is general and can adapt to parent bounds and child views of any size.

Figure 1: The movement of these flowers is bounded into the black rectangle.

Testing Touches

Most onscreen view elements for direct manipulation interfaces are not rectangular. This complicates touch detection because parts of the actual view rectangle may not correspond to actual touch points. Figure 2 shows the problem in action. The screenshot on the right shows the interface with its touch-based subviews. The shot on the left shows the actual view bounds for each subview. The light gray areas around each onscreen circle fall within the bounds, but touches to those areas should not "hit" the view in question.

Figure 2: The application should ignore touches to the gray areas that surround each circle (left). The actual interface (right) uses a clear background (zero alpha values) to hide the parts of the view that are not used.

iOS senses user taps throughout the entire view frame. This includes the undrawn area, such as the corners of the frame outside the actual circles of Figure 2, just as much as the primary presentation. That means that unless you add some sort of hit test, users may attempt to tap through to a view that's "obscured" by the clear portion of the UIView frame. Visualize your actual view bounds by setting its background color, for example:

dragger.backgroundColor = [UIColor lightGrayColor];

This adds the backsplashes shown in Figure 2 (left) without affecting the actual onscreen art. In this case, the art consists of a centered circle with a transparent background. Unless you add some sort of test, all taps to any portion of this frame are captured by the view in question. Enabling background colors offers a convenient debugging aid to visualize the true extent of each view; don't forget to comment out the background color assignment in production code. Alternatively, you can set a view layer's border width or style.

Recipe 5 adds a simple hit test to the views, determining whether touches fall within the circle. This test overrides the standard UIView's pointInside:withEvent: method. This method returns either YES (the point falls inside the view) or NO (it does not). The test here uses basic geometry, checking whether the touch lies within the circle's radius. You can provide any test that works with your onscreen views. (As you will see in Recipe 6, that test can be expanded for much finer control.)

Be aware that the math for touch detection on Retina Display devices remains the same as that for older units. The extra onboard pixels do not affect your gesture-handling math. Your view's coordinate system remains floating point with subpixel accuracy. The number of pixels the device uses to draw to the screen does not affect UIView bounds and UITouch coordinates; it simply provides a way to provide higher detail graphics within that coordinate system.

Do not confuse the point-inside test, which checks whether a point falls inside a view, with the similar-sounding hitTest:withEvent:. The hit test returns the topmost view (closest to the user/screen) in a view hierarchy that contains a specific point. It works by calling pointInside:withEvent: on each view. If the point inside method returns YES, the search continues down that hierarchy.

Testing Against a Bitmap

Unfortunately, most views don't fall into the simple geometries that make the hit test from Recipe 5 so straightforward. The flowers shown in Figure 1, for example, offer irregular boundaries and varied transparencies. For complicated art, it helps to test touches against a bitmap. Bitmaps provide byte-by-byte information about the contents of an image-based view, allowing you to test whether a touch hits a solid portion of the image or should pass through to any views below.

Recipe 6 extracts an image bitmap from a UIImageView. It assumes that the image used provides a pixel-by-pixel representation of the view in question. When you distort that view (normally by resizing a frame or applying a transform), update the math accordingly. CGPoints can be transformed via CGPointApplyAffineTransform() to handle scaling and rotation changes. Keeping the art at a 1:1 proportion to the actual view pixels simplifies lookup and avoids any messy math. You can recover the pixel in question, test its alpha level, and determine whether the touch has hit a solid portion of the view.

This example uses a cutoff of 85. That corresponds to a minimum alpha level of 33% (that is, 85/255). This custom pointInside: method considers any pixel with an alpha level below 33% to be transparent. This is arbitrary. Use any level (or other test, for that matter) that works with the demands of your actual GUI. Unless you need pixel-perfect touch detection, you can probably scale down the bitmap so that it uses less memory and adjust the detection math accordingly.

Summary

UIViews and their underlying layers provide the onscreen components your users see. Touch input lets users interact directly with views via the UITouch class and gesture recognizers. As this article has shown, even in their most basic form, touch-based interfaces offer easy-to-implement flexibility and power. In a future article, we will expand your skill set with onscreen drawing, touch-based painting, creating smooth drawings, multi-touch interactions, and more.

Erica is an expert in iOS development and writes frequently on the topic. She holds a Ph. D. in Computer Science from Georgia Tech's Graphics, Visualization and Usability Center. This article was excerpted from a late draft of her Core iOS 6 Developer's Cookbook, 4th Ed. Although it has been reviewed technically, final presentation and content in the book may vary from what was presented here.

Dr. Dobb's encourages readers to engage in spirited, healthy debate, including taking us to task.
However, Dr. Dobb's moderates all comments posted to our site, and reserves the right to modify or remove any content that it determines to be derogatory, offensive, inflammatory, vulgar, irrelevant/off-topic, racist or obvious marketing or spam. Dr. Dobb's further reserves the right to disable the profile of any commenter participating in said activities.

Video

This month's Dr. Dobb's Journal

This month,
Dr. Dobb's Journal is devoted to mobile programming. We introduce you to Apple's new Swift programming language, discuss the perils of being the third-most-popular mobile platform, revisit SQLite on Android
, and much more!