我的应用程序中有自定义视图,可以由用户滚动.但是,此视图不会从UIScrollView继承.现在我希望用户能够将此视图滚动到顶部,就像任何其他可滚动视图允许的那样.我认为没有直接的方法可以做到这一点.
Google提出了一个解决方案:http://cocoawithlove.com/2009/05/intercepting-status-bar-touches-on.html这不再适用于iOS 4.x. 那是不行的.
我有想法创建一个scrollview并将其保存在某个地方,只是为了捕获它的通知然后将它们转发给我的控件.这不是解决我的问题的好方法,所以我正在寻找"更清洁"的解决方案.我喜欢前面提到的UIApplication子类链接的一般方法.但是什么API可以给我可靠的信息?
有什么想法,帮助等......?
编辑:我不喜欢我当前解决方案的另一件事是它只有在当前视图没有任何滚动视图时才有效.滚动到顶部的手势只有在周围只有一个滚动视图时才有效.只要将虚拟添加到具有另一个滚动视图的视图(请参阅下面的详细说明),手势就会完全禁用.寻找更好解决方案的另一个原因......
最后,我从这里的答案中汇总了工作解决方案.感谢你们.
在某处声明通知名称(例如AppDelegate.h):
static NSString * const kStatusBarTappedNotification = @"statusBarTappedNotification";
将以下行添加到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]; }
观察所需控制器中的通知(例如,在viewWillAppear中):
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(statusBarTappedAction:) name:kStatusBarTappedNotification object:nil];
正确删除观察者(例如在viewDidDisappear中):
[[NSNotificationCenter defaultCenter] removeObserver:self name:kStatusBarTappedNotification object:nil];
实现通知处理回调:
- (void)statusBarTappedAction:(NSNotification*)notification { NSLog(@"StatusBar tapped"); //handle StatusBar tap here. }
希望它会有所帮助.
Swift 3更新
测试并适用于iOS 9+.
在某处声明通知名称:
let statusBarTappedNotification = Notification(name: Notification.Name(rawValue: "statusBarTappedNotification"))
跟踪状态栏触摸和发布通知.将以下行添加到AppDelegate.swift:
override func touchesBegan(_ touches: Set, 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) } }
必要时观察通知:
NotificationCenter.default.addObserver(forName: statusBarTappedNotification.name, object: .none, queue: .none) { _ in print("status bar tapped") }
所以这是我目前的解决方案,效果非常好.但请带上其他想法,因为我不喜欢它...
在视图中的某处添加滚动视图.也许隐藏它或将其放在其他视图之下等.
设置它contentSize
大于边界
设置非零 contentOffset
在您的控制器中实现scrollview的委托,如下所示.
通过始终返回NO
,滚动视图永远不会向上滚动,只要用户点击状态栏,就会收到通知.但问题是,这不适用于"真实"内容滚动视图.(见问题)
- (BOOL)scrollViewShouldScrollToTop:(UIScrollView *)scrollView { // Do your action here return NO; }
将此添加到AppDelegate.swift将执行您想要的操作:
override func touchesBegan(touches: Set, withEvent event: UIEvent?) { super.touchesBegan(touches, withEvent: event) let events = event!.allTouches() let touch = events!.first let location = touch!.locationInView(self.window) let statusBarFrame = UIApplication.sharedApplication().statusBarFrame if CGRectContainsPoint(statusBarFrame, location) { NSNotificationCenter.defaultCenter().postNotificationName("statusBarSelected", object: nil) } }
现在您可以根据需要订阅活动:
NSNotificationCenter.defaultCenter().addObserverForName("statusBarSelected", object: nil, queue: nil) { event in // scroll to top of a table view self.tableView!.setContentOffset(CGPointZero, animated: true) }
找到了一个更好的iOS7兼容解决方案:http://ruiaureliano.tumblr.com/post/37260346960/uitableview-tap-status-bar-to-scroll-up
将此方法添加到AppDelegate:
- (void) touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event { [super touchesBegan:touches withEvent:event]; CGPoint location = [[[event allTouches] anyObject] locationInView:[self window]]; if (CGRectContainsPoint([UIApplication sharedApplication].statusBarFrame, location)) { NSLog(@"STATUS BAR TAPPED!"); } }
我通过在状态栏上添加一个清晰的UIView然后拦截触摸事件来实现这一点
首先在Application委托应用程序中:didFinishLaunchingWithOptions:添加以下两行代码:
self.window.backgroundColor = [UIColor clearColor]; self.window.windowLevel = UIWindowLevelStatusBar+1.f;
然后在视图控制器中,您希望拦截状态栏点击(或在应用程序委托中)添加以下代码
UIView* statusBarInterceptView = [[[UIView alloc] initWithFrame:[UIApplication sharedApplication].statusBarFrame] autorelease]; statusBarInterceptView.backgroundColor = [UIColor clearColor]; UITapGestureRecognizer* tapRecognizer = [[[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(statusBarClicked)] autorelease]; [statusBarInterceptView addGestureRecognizer:tapRecognizer]; [[[UIApplication sharedApplication].delegate window] addSubview:statusBarInterceptView];
在statusBarClicked选择器中,执行您需要执行的操作,在我的情况下,我向通知中心发布了通知,以便其他视图控制器可以响应状态栏点击.
谢谢Max,您的解决方案经过多年的努力寻找后,对我有用.
有关信息:
dummyScrollView = [[UIScrollView alloc] init]; dummyScrollView.delegate = self; [view addSubview:dummyScrollView]; [view sendSubviewToBack:dummyScrollView];
然后
dummyScrollView.contentSize = CGSizeMake(view.frame.size.width, view.frame.size.height+200); // scroll it a bit, otherwise scrollViewShouldScrollToTop not called dummyScrollView.contentOffset = CGPointMake(0, 1); //delegate : - (BOOL)scrollViewShouldScrollToTop:(UIScrollView *)scrollView { // DETECTED! - do what you need to NSLog(@"scrollViewShouldScrollToTop"); return NO; }
请注意,我还有一个UIWebView,我不得不破解我在某处找到的解决方案:
- (void)webViewDidFinishLoad:(UIWebView *)wv { [super webViewDidFinishLoad:wv]; UIScrollView *scroller = (UIScrollView *)[[webView subviews] objectAtIndex:0]; if ([scroller respondsToSelector:@selector(setScrollEnabled:)]) scroller.scrollEnabled = NO; }