I have custom view in my application which can be scrolled by the user. This view, however, does not inherit from UIScrollView. Now I want the user to be able to scroll this view to the top, just as any other scrollable view allows. I figured that there is no direct way to do so.
Google turned up one solution: http://cocoawithlove.com/2009/05/intercepting-status-bar-touches-on.html This no longer works on iOS 4.x. That's a no-go.
I had the idea of creating a scrollview and keeping it around somewhere, just to catch it's notifications and then forward them to my control. This is not a nice way to solve my problem, so I am looking for "cleaner" solutions. I like the general approach of the aforementioned link to subclass UIApplication. But what API can give me reliable info?
Are there any thoughts, help, etc...?
Edit: Another thing I don't like about my current solution is that it only works as long as the current view does not have any scroll views. The scroll-to-top gesture works only if exactly one scroll view is around. As soon as the dummy is added (see my answer below for details) to a view with another scrollview, the gesture is completely disabled. Another reason to look for a better solution...
Finally, i've assembled the working solution from answers here. Thank you guys.
Declare notification name somewhere (e.g. AppDelegate.h):
static NSString * const kStatusBarTappedNotification = @"statusBarTappedNotification";
Add following lines to your AppDelegate.m:
#pragma mark - Status bar touch tracking
- (void) touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {
[super touchesBegan:touches withEvent:event];
CGPoint location = [[[event allTouches] anyObject] locationInView:[self window]];
CGRect statusBarFrame = [UIApplication sharedApplication].statusBarFrame;
if (CGRectContainsPoint(statusBarFrame, location)) {
[self statusBarTouchedAction];
}
}
- (void)statusBarTouchedAction {
[[NSNotificationCenter defaultCenter] postNotificationName:kStatusBarTappedNotification
object:nil];
}
Observe notification in the needed controller (e.g. in viewWillAppear):
[[NSNotificationCenter defaultCenter] addObserver:self
selector:@selector(statusBarTappedAction:)
name:kStatusBarTappedNotification
object:nil];
Remove observer properly (e.g. in viewDidDisappear):
[[NSNotificationCenter defaultCenter] removeObserver:self name:kStatusBarTappedNotification object:nil];
Implement notification-handling callback:
- (void)statusBarTappedAction:(NSNotification*)notification {
NSLog(@"StatusBar tapped");
//handle StatusBar tap here.
}
Hope it will help.
Swift 3 update
Tested and works on iOS 9+.
Declare notification name somewhere:
let statusBarTappedNotification = Notification(name: Notification.Name(rawValue: "statusBarTappedNotification"))
Track status bar touches and post notification. Add following lines to your AppDelegate.swift:
override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
super.touchesBegan(touches, with: event)
let statusBarRect = UIApplication.shared.statusBarFrame
guard let touchPoint = event?.allTouches?.first?.location(in: self.window) else { return }
if statusBarRect.contains(touchPoint) {
NotificationCenter.default.post(statusBarTappedNotification)
}
}
Observe notification where necessary:
NotificationCenter.default.addObserver(forName: statusBarTappedNotification.name, object: .none, queue: .none) { _ in
print("status bar tapped")
}
So this is my current solution, which works amazingly well. But please come with other ideas, as I don't really like it...
contentSize
to be larger than the boundscontentOffset
By always returning NO
, the scroll view never scrolls up and one gets a notification whenever the user hits the status bar. The problem is, however, that this does not work with a "real" content scroll view around. (see question)
- (BOOL)scrollViewShouldScrollToTop:(UIScrollView *)scrollView
{
// Do your action here
return NO;
}
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