Okay I tested the following with the tabbed application template on Xcode 4.5/iOS 6.
Created a UIButton subclass called SampleButton and implemented the following mothods:
- (void)touchesBegan:(NSSet *)touches
withEvent:(UIEvent *)event
{
[super touchesBegan:touches withEvent:event];
}
- (void)touchesCancelled:(NSSet *)touches
withEvent:(UIEvent *)event
{
[super touchesCancelled:touches withEvent:event];
}
- (void) touchesMoved:(NSSet *)touches
withEvent:(UIEvent *)event
{
[super touchesMoved:touches withEvent:event];
}
- (void)touchesEnded:(NSSet *)touches
withEvent:(UIEvent *)event
{
[super touchesEnded:touches withEvent:event];
}
Added this SampleButton to the first tab.
RESULT: View switches to second tab but touchesCancelled and/or touchesEnded are never called in SampleButton. Shouldn't one or the other of those fire if the view changes while I'm touching that button? This is proving to be a huge issue because, in my app I'm playing a sound while that button is down and it never stops playing if the user switches tabs while pressing it. Seems like this used to work fine in iOS3 and iOS4.
It appears that when a view is removed from its window, it dissociates itself from any touches that were associated with it. So when the touch finally ends, the system doesn't send touchesEnded:…
or touchesCancelled:…
to the view.
If you want to just disable tab switching while the button is pressed, you can do that by giving the tab bar controller a delegate and having the delegate return NO
from tabBarController:shouldSelectViewController:
. For example, in the your test app, you can have FirstViewController
make itself the tab bar controller's delegate:
- (void)viewWillAppear:(BOOL)animated {
self.tabBarController.delegate = self;
}
And the view controller can allow the tab bar controller to select a tab only when the button is not pressed (highlighted):
- (BOOL)tabBarController:(UITabBarController *)tabBarController shouldSelectViewController:(UIViewController *)viewController {
return !_button.highlighted;
}
When the button is removed from its window, it resets its highlighted
property to NO
. So one generic way to work around this problem is by using key-value observing (KVO) to monitor the button's state (instead of relying on the button to send you actions). Set yourself up as an observer of the button's highlighted
property like this:
static int kObserveButtonHighlightContext;
- (void)viewDidLoad {
[super viewDidLoad];
[_button addObserver:self forKeyPath:@"highlighted"
options:NSKeyValueObservingOptionOld
context:&kObserveButtonHighlightContext];
}
- (void)dealloc {
[_button removeObserver:self forKeyPath:@"highlighted"
context:&kObserveButtonHighlightContext];
}
I discovered in testing that the button sends an extra KVO notification when it's removed from the window, before it resets its highlighted
property back to NO
. So when handling the KVO notification, check that the value has actually changed:
- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context {
if (context == &kObserveButtonHighlightContext) {
if ([change[NSKeyValueChangeOldKey] boolValue] != _button.highlighted) {
[self updatePlaybackForButtonState];
}
} else {
[super observeValueForKeyPath:keyPath ofObject:object change:change context:context];
}
}
Finally, start or stop playback according to the highlighted
property of the button:
- (void)updatePlaybackForButtonState {
if (_button.highlighted) {
NSLog(@"start playback");
} else {
NSLog(@"end playback");
}
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With