Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

UINavigationItem Back Button touch area too large

On this following screenshot, if I click on "v" from "Available Kiosks" this is launching the action of the back button... (not with the second "a").

alt text

I don't understand why, I've nothing special in my code (this is the default backbutton handled by the navigation controller). I also have the same bug with another application I did but I never notice this on others applications.

Any Ideas ?

Thank you.

like image 384
William Remacle Avatar asked Oct 12 '10 08:10

William Remacle


2 Answers

That's not a bug, it does the same in Apple apps, and even on some (many / all ?) buttons. It's the behaviour of touch events on buttons : the area of the touch is larger than the button bounds.

like image 148
Oliver Avatar answered Nov 13 '22 15:11

Oliver


I needed to do the same thing and so I ended up swizzling the UINavigationBar touchesBegan:withEvent method and checking the y coordinate of the touch before calling the original method.
This means that when the touch was too close to a button that I was using under the Navigation I could cancel it.

Ex:The back button almost always captured the touch event instead of the "First" Button enter image description here

Here is my category:

@implementation UINavigationBar (UINavigationBarCategory)
- (void)sTouchesEnded:(NSSet *)touches withEvent:(UIEvent *)event
{
float maxY = 0;
for (UITouch *touch in touches) {
    float touchY = [touch locationInView:self].y;
    if ( [touch locationInView:self].y > maxY) maxY = touchY;
}

NSLog(@"swizzlelichious bar touchY %f", maxY);

if (maxY < 35 )
    [self sTouchesEnded:touches withEvent:event];
else 
    [self touchesCancelled:touches withEvent:event];
}
- (void)sTouchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{
float maxY = 0;
for (UITouch *touch in touches) {
    float touchY = [touch locationInView:self].y;
    if ( [touch locationInView:self].y > maxY) maxY = touchY;
}

NSLog(@"swizzlelichious bar touchY %f", maxY);

if (maxY < 35 )
    [self sTouchesBegan:touches withEvent:event];
else 
    [self touchesCancelled:touches withEvent:event];
}

The swizzle implementation by Mike Ash from CocoaDev

void Swizzle(Class c, SEL orig, SEL new)
{
Method origMethod = class_getInstanceMethod(c, orig);
Method newMethod = class_getInstanceMethod(c, new);
if(class_addMethod(c, orig, method_getImplementation(newMethod), method_getTypeEncoding(newMethod)))
    class_replaceMethod(c, new, method_getImplementation(origMethod), method_getTypeEncoding(origMethod));
else
    method_exchangeImplementations(origMethod, newMethod);
}

And the function calls to the swizzle function

Swizzle([UINavigationBar class], @selector(touchesEnded:withEvent:), @selector(sTouchesEnded:withEvent:));
Swizzle([UINavigationBar class], @selector(touchesBegan:withEvent:), @selector(sTouchesBegan:withEvent:));

I don't know if Apple is ok with this, it might be infringing on their UI guidelines, I will try to update the post if after I submit the app to the app store.

like image 34
filo Avatar answered Nov 13 '22 13:11

filo