我的应用程序中有自定义视图,可以由用户滚动。但是,此视图不会从UIScrollView继承。现在我希望用户能够将此视图滚动到顶部,就像任何其他可滚动视图所允许的那样。我认为没有直接的方法可以这样做。
Google提出了一个解决方案:http://cocoawithlove.com/2009/05/intercepting-status-bar-touches-on.html这不再适用于iOS 4.x.那是不行的。
我有想法创建一个scrollview并将其保存在某处,只是为了捕获它的通知,然后将它们转发给我的控件。这不是解决我的问题的好方法,所以我正在寻找“更清洁”的解决方案。我喜欢前面提到的UIApplication子类链接的一般方法。但是什么API可以给我可靠的信息?
有任何想法,帮助等......?
编辑:我不喜欢当前解决方案的另一件事是,只有当前视图没有任何滚动视图时,它才有效。滚动到顶部的手势只有在周围只有一个滚动视图时才有效。只要将虚拟添加到具有另一个滚动视图的视图(请参阅下面的详细说明),手势就会完全禁用。寻找更好解决方案的另一个原因......
答案 0 :(得分:50)
最后,我从这里的答案中汇总了工作解决方案。感谢你们。
在某处声明通知名称(例如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<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)
}
}
在必要时观察通知:
NotificationCenter.default.addObserver(forName: statusBarTappedNotification.name, object: .none, queue: .none) { _ in
print("status bar tapped")
}
答案 1 :(得分:28)
所以这是我目前的解决方案,效果非常好。但请带上其他想法,因为我不喜欢它......
contentSize
设置为大于边界contentOffset
通过始终返回NO
,滚动视图永远不会向上滚动,只要用户点击状态栏,就会收到通知。但问题是,这不适用于“真实”内容滚动视图。 (见问题)
- (BOOL)scrollViewShouldScrollToTop:(UIScrollView *)scrollView
{
// Do your action here
return NO;
}
答案 2 :(得分:14)
将此添加到AppDelegate.swift将执行您想要的操作:
override func touchesBegan(touches: Set<UITouch>, 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)
}
答案 3 :(得分:11)
找到了一个更好的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!");
}
}
答案 4 :(得分:10)
我通过在状态栏上添加一个清晰的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选择器中,执行您需要执行的操作,在我的情况下,我向通知中心发布了通知,以便其他视图控制器可以响应状态栏点击。
答案 5 :(得分:8)
谢谢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;
}
答案 6 :(得分:4)
您可以使用以下代码跟踪状态栏点按:
[[NSNotificationCenter defaultCenter] addObserverForName:@"_UIApplicationSystemGestureStateChangedNotification"
object:nil
queue:nil
usingBlock:^(NSNotification *note) {
NSLog(@"Status bar pressed!");
}];
答案 7 :(得分:2)
使用不可见的UIScrollView
。在iOS 10和iOS测试斯威夫特3。
override func viewDidLoad() {
let scrollView = UIScrollView()
scrollView.bounds = view.bounds
scrollView.contentOffset.y = 1
scrollView.contentSize.height = view.bounds.height + 1
scrollView.delegate = self
view.addSubview(scrollView)
}
func scrollViewShouldScrollToTop(_ scrollView: UIScrollView) -> Bool {
debugPrint("status bar tapped")
return false
}
答案 8 :(得分:1)
一种方式,可能不是最好的,可能是在状态栏上方放置一个清晰的UIView并拦截UIView的触摸,如果没有其他的话可能会帮助你...
答案 9 :(得分:1)
如果您只是在点击状态栏时尝试将UIScrollView
滚动到顶部,则值得注意的是,这是默认行为IF 您的视图控制器在其子视图中只有一个UIScrollView
,scrollsToTop
设置为YES
。
所以我必须去查找任何其他UIScrollView
(或子类:UITableView
,UICollectionView
,并将scrollsToTop
设置为NO
。< / p>
公平地说,我在原始问题的post that was linked to中找到了这个信息,但它也因为不再工作而被驳回,所以我跳过它并且只在随后的搜索中找到了相关的部分。
答案 10 :(得分:1)
对于iOS 13来说,这对我来说很有效,UIStatusBarManager
的Objective-C类别
@implementation UIStatusBarManager (CAPHandleTapAction)
-(void)handleTapAction:(id)arg1 {
// Your code here
}
@end