rob
rob

Reputation: 4119

How do I respond to a touch *down* event in the UITabbar

I'd like to begin animating a UITabBarItem when the user touches down on the tab. However, UITabBarDelegate only provides a didSelect method. What's the best way of detecting a UIControlEvents.touchDown event in this context?

Upvotes: 3

Views: 358

Answers (1)

yaronalk
yaronalk

Reputation: 74

You subclass UITabBar and override hitTest:withEvent:

Here's an example of a subclass that slightly scales down the image upon touch-down, then restores it upon touch-up-inside

@interface TRCTabBar : UITabBar

@end


@implementation TRCTabBar

- (UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event {
    UIView *view = [super hitTest:point withEvent:event];
    if ([view isKindOfClass:UIControl.class]) {
        CGFloat scale = 0.90;
        CGAffineTransform t = CGAffineTransformScale(CGAffineTransformIdentity, scale, scale);
        [UIView animateWithDuration:0.14 delay:0 options:UIViewAnimationOptionAllowUserInteraction animations:^{
            view.transform = t;
        } completion:nil];
    }
    return view;
}

// used as a signal to restore the image back to its original state
- (void)setSelectedItem:(UITabBarItem *)selectedItem {
    [super setSelectedItem:selectedItem];
    for (UIView *view in self.subviews) {
        if (!CGAffineTransformIsIdentity(view.transform)) {
            view.transform = CGAffineTransformIdentity;
        }
    }
}

@end

Some notes:

  1. Unlike the touch-down event that's accessed via hitTest:withEvent:, the touch-up-inside event isn't accessed directly; Simply override setSelectedItem: to have a chance to perform some actions when the user lifts their finger.

  2. There's no way to monitor a touch-up-outside (or any other cancellation event, for this matter). So if a user taps, then drags outside, then lifts their finger, the image remains scaled down until next setSelectedItem: is called.

  3. If you use animations (like in my provided example code), you must use the UIViewAnimationOptionAllowUserInteraction option. Otherwise setSelectedItem: isn't always called.

  4. You only want to pick up touches from the UITabBarButton class (that's the control that responds to the touch-down event). A user may also accidentally touch the UITabBar itself, and you should ignore this touch. UITabBarButton is an internal UIKit class, but it's a subclass of UIControl. Use that to filter out all other ignored UIViews (like the UITabBar itself).

  5. Obviously, make sure to set your UITabBar's class (in Interface Builder or programatically) as your custom class.

Upvotes: 1

Related Questions