Tom K
Tom K

Reputation: 440

UIControl tracking touch that started on a different UIControl

I am making a custom iOS keyboard and have a UIControl subclass to represent my button. I am trying to get the same behaviour as the normal iOS keyboard:

  1. User begins touch on one button
  2. User drags over other buttons (need to detect this so they can highlight/dehighlight accordingly)
  3. Register the actual keyboard "press" when the user lifts their finger; that is, the touch ends

I am testing using the touch tracking methods like this:

- (BOOL)beginTrackingWithTouch:(UITouch *)touch withEvent:(UIEvent *)event
{
    [super beginTrackingWithTouch:touch withEvent:event];
    NSLog(@"Begin for %@", [self label]);
    return YES;
}

- (BOOL)continueTrackingWithTouch:(UITouch *)touch withEvent:(UIEvent *)event
{
    [super continueTrackingWithTouch:touch withEvent:event];
    NSLog(@"Continue for %@", [self label]);
    return YES;
}

- (void)endTrackingWithTouch:(UITouch *)touch withEvent:(UIEvent *)event
{
    [super endTrackingWithTouch:touch withEvent:event];
    NSLog(@"End for %@", [self label]);
}

These methods are all called, except they are only ever called on the UIControl where the touch began.

What is the best way to recognise touches coming and going across all my buttons? Do I have to do it all via the parent view?

Upvotes: 2

Views: 1069

Answers (2)

DeFrenZ
DeFrenZ

Reputation: 2262

I think that you should have a single big UIControl which has different subviews (like UIButton) but tracks touches by itself like you did already but finds out which subview to highlight depending on the touch position.

Upvotes: -1

Tom K
Tom K

Reputation: 440

I'll select a better answer if offered... but in case anybody finds this by search, I've managed to get what I need this way:

  • Set userInteractionEnabled to NO for the button class (UIControl subclass)
  • Don't override any touch methods in the button class
  • Implement touchesBegan:withEvent:, touchesMoved:withEvent: and touchesEnded:withEvent: in the view controller
  • On each event, extract the location from the UITouch object
  • Iterate over all of the button subviews and find the one containing the touch location:

    - (MyButton *)buttonForTouch:(UITouch *)touch
    {
        CGPoint windowLocation = [touch locationInView:keyboardView];
        for (MyButton *button in buttons) {
            if (CGRectContainsPoint([button frame], windowLocation)) {
                return button;
            }
        }
        return nil;
    }
    
  • Having determined which button the user is interacting with, make the view controller send messages to the relevant buttons to adjust their appearance

  • If appropriate, keep a reference to the UITouch instance in touchesBegan:withEvent: so you can be sure that you're tracking the same one in the other methods

Upvotes: 2

Related Questions