Friday, March 28, 2008

Eureka!  Well it's not that much of a victory, but on a new platform, and one with a super shiny screen it's fun to see your code work.  So far developing for the iPhone is remarkably easy.  There are lots of framework objects and samples to get you started with simple applications.  The first thing I wanted to do was use the screen to interpret finger swipes.  You would think this would be built in, and according to the documentation, it is.  However I couldn't get it to work in the emulator.  Here is the sample code Apple provided to intercept swipes.

// Handles the continuation of a touch.
- (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event
{  
    // Enumerates through all touch objects
    for (UITouch *touch in touches){
        if (touch.info & UITouchInfoSwipedDown) {
            touchInfoText.text = @"Swipe down";
        } else if (touch.info & UITouchInfoSwipedUp) {
            touchInfoText.text = @"Swipe up";
        } else if (touch.info & UITouchInfoSwipedRight) {
            touchInfoText.text = @"Swipe right";
        } else if (touch.info & UITouchInfoSwipedLeft) {
            touchInfoText.text = @"Swipe left";
        } 
        // Send to the dispatch method, which will make sure the appropriate subview is acted upon
        [self dispatchTouchEvent:[touch view] toPosition:[touch locationInView:self]];
    }
}

touchesMoved is a call back that gets executed while your finger is still moving across the screen.  Checking the .info member variable against an enumerated bit mask should do the trick.  In my simulator I could never get these events to fire while dragging across the screen, so I rolled my own.  It's pretty straight forward, but it works and I get all of the expected outputs on my cool little app.

#pragma mark -
#pragma mark === Touch handling  ===
#pragma mark
 
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{
    _labelDirection.text = @"";
 
    // Save the position
    for (UITouch *touch in touches) {
        // Send to the dispatch method, which will make sure the appropriate subview is acted upon
        [self dispatchFirstTouchAtPoint:[touch locationInView:self] forEvent:nil];
    }
}
 
// Saves the first position for reference when the user lets go.
-(void) dispatchFirstTouchAtPoint:(CGPoint)touchPoint forEvent:(UIEvent *)event
{
    _myTouchPoint = touchPoint;
}
 
// Handles the continuation of a touch.
- (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event
{  
    for (UITouch *touch in touches) {
        // Send to the dispatch method, which will make sure the appropriate subview is acted upon
        [self dispatchTouchEndEvent:[touch view] toPosition:[touch locationInView:self]];
    }
}
 
#define MIN_SWIPE_DISTANCE 10
 
// Diffs the start and end points of the swipe to determine direction
-(void) dispatchTouchEndEvent:(UIView *)theView toPosition:(CGPoint)position
{   
    CGFloat xDelta = position.x - _myTouchPoint.x;
    CGFloat yDelta = position.y - _myTouchPoint.y;
 
    // We only want to see large strokes
    if(abs(xDelta) > MIN_SWIPE_DISTANCE || abs(yDelta) > MIN_SWIPE_DISTANCE)
    {
        // See which way the stroke went
        if(abs(xDelta) > abs(yDelta)) {
            if(xDelta > 0) {
                _labelDirection.text = @"Right";
            }
            else {
                _labelDirection.text = @"Left";        
            }
        }
        else
        {
            if(yDelta > 0) {
                _labelDirection.text = @"Down";
            }
            else {
                _labelDirection.text = @"Up";
            }
        }
    }
    // Short distances are considered clicks
    else
    {
        _labelDirection.text = @"Click";    
    }
}

touchesBegan and touchesEnded are also call backs that get executed when you think they would, when your finger touches and then leaves the screen.  I use a little subtraction and the magic of absolute value to determine the drag direction.  Small drags are considered clicks.  Now I'm ready to plug any code into my directions.  This doesn't use the delta or the accelerometer that are available, but for my purposes I just need a direction at this point.

Code | iPhone