ios 如何检测状态栏中的触摸
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/3753097/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
How to detect touches in status bar
提问by Max Seelemann
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.
我的应用程序中有自定义视图,可以由用户滚动。但是,此视图不是从 UIScrollView 继承的。现在我希望用户能够将此视图滚动到顶部,就像任何其他可滚动视图允许的那样。我认为没有直接的方法可以做到这一点。
Google turned up one solution: http://cocoawithlove.com/2009/05/intercepting-status-bar-touches-on.htmlThis no longer works on iOS 4.x. That's a no-go.
谷歌提出了一种解决方案:http: //cocoawithlove.com/2009/05/intercepting-status-bar-touches-on.html这不再适用于 iOS 4.x。那是不行的。
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?
我的想法是创建一个滚动视图并将其保存在某个地方,只是为了捕捉它的通知,然后将它们转发给我的控件。这不是解决我的问题的好方法,所以我正在寻找“更干净”的解决方案。我喜欢上述链接到 UIApplication 子类的一般方法。但是什么 API 可以给我可靠的信息?
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...
编辑:我不喜欢当前解决方案的另一件事是,它仅在当前视图没有任何滚动视图时才有效。只有当只有一个滚动视图存在时,滚动到顶部手势才有效。一旦将虚拟对象添加到具有另一个滚动视图的视图中(有关详细信息,请参阅下面的答案),该手势将被完全禁用。寻找更好解决方案的另一个原因......
采纳答案by Max Seelemann
So this is my current solution, which works amazingly well. But please come with other ideas, as I don't really like it...
所以这是我目前的解决方案,效果非常好。但是请提出其他想法,因为我真的不喜欢它......
- Add a scrollview somewhere in your view. Maybe hide it or place it below some other view etc.
- Set its
contentSize
to be larger than the bounds - Set a non-zero
contentOffset
- In your controller implement a delegate of the scrollview like shown below.
- 在您的视图中的某处添加一个滚动视图。也许隐藏它或将它放在其他视图下方等。
- 将其
contentSize
设置为大于边界 - 设置一个非零
contentOffset
- 在您的控制器中实现滚动视图的委托,如下所示。
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)
通过始终返回NO
,滚动视图永远不会向上滚动,并且每当用户点击状态栏时都会收到通知。然而,问题是这不适用于“真实”内容滚动视图。(见问题)
- (BOOL)scrollViewShouldScrollToTop:(UIScrollView *)scrollView
{
// Do your action here
return NO;
}
回答by Eugene Tartakovsky
Finally, i've assembled the working solution from answers here. Thank you guys.
最后,我从这里的答案中收集了工作解决方案。谢谢你们。
Declare notification name somewhere (e.g. AppDelegate.h):
在某处声明通知名称(例如 AppDelegate.h):
static NSString * const kStatusBarTappedNotification = @"statusBarTappedNotification";
Add following lines to your AppDelegate.m:
将以下行添加到您的 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):
观察所需控制器中的通知(例如在 viewWillAppear 中):
[[NSNotificationCenter defaultCenter] addObserver:self
selector:@selector(statusBarTappedAction:)
name:kStatusBarTappedNotification
object:nil];
Remove observer properly (e.g. in viewDidDisappear):
正确移除观察者(例如在 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
斯威夫特 3 更新
Tested and works on iOS 9+.
经过测试并适用于 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:
跟踪状态栏触摸并发布通知。将以下行添加到您的 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")
}
回答by DTHENG
Adding this to your AppDelegate.swift will do what you want:
将此添加到您的 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)
}
}
Now you can subscribe to the event where ever you need:
现在,您可以在任何需要的地方订阅该事件:
NSNotificationCenter.defaultCenter().addObserverForName("statusBarSelected", object: nil, queue: nil) { event in
// scroll to top of a table view
self.tableView!.setContentOffset(CGPointZero, animated: true)
}
回答by amleszk
Found a much better solution which is iOS7 compatible here :http://ruiaureliano.tumblr.com/post/37260346960/uitableview-tap-status-bar-to-scroll-up
在这里找到了一个与 iOS7 兼容的更好的解决方案:http://ruiaureliano.tumblr.com/post/37260346960/uitableview-tap-status-bar-to-scroll-up
Add this method to your AppDelegate:
将此方法添加到您的 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!");
}
}
回答by manggit
I implemented this by adding a clear UIView over the status bar and then intercepting the touch events
我通过在状态栏上添加一个清晰的 UIView 然后拦截触摸事件来实现这一点
First in your Application delegate application:didFinishLaunchingWithOptions: add these 2 lines of code:
首先在您的应用程序委托 application:didFinishLaunchingWithOptions: 添加以下两行代码:
self.window.backgroundColor = [UIColor clearColor];
self.window.windowLevel = UIWindowLevelStatusBar+1.f;
Then in the view controller you wish to intercept status bar taps (or in the application delegate) add the following code
然后在您希望拦截状态栏点击的视图控制器中(或在应用程序委托中)添加以下代码
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];
In the statusBarClicked selector, do what you need to do, in my case I posted a notification to the notification center so that other view controllers can respond to the status bar tap.
在 statusBarClicked 选择器中,做你需要做的事情,在我的例子中,我向通知中心发布了一个通知,以便其他视图控制器可以响应状态栏点击。
回答by JohnDugdale
Thanks Max, your solution worked for me after spending ages looking.
谢谢 Max,你的解决方案在我花了很长时间寻找之后对我有用。
For information :
信息:
dummyScrollView = [[UIScrollView alloc] init];
dummyScrollView.delegate = self;
[view addSubview:dummyScrollView];
[view sendSubviewToBack:dummyScrollView];
then
然后
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;
}
Note that I had a UIWebView also which I had to hack a bit with a solution I found somewhere :
请注意,我也有一个 UIWebView,我不得不用我在某处找到的解决方案来破解一下:
- (void)webViewDidFinishLoad:(UIWebView *)wv
{
[super webViewDidFinishLoad:wv];
UIScrollView *scroller = (UIScrollView *)[[webView subviews] objectAtIndex:0];
if ([scroller respondsToSelector:@selector(setScrollEnabled:)])
scroller.scrollEnabled = NO;
}
回答by Aron Balog
You can track status bar tap by using following code:
您可以使用以下代码跟踪状态栏点击:
[[NSNotificationCenter defaultCenter] addObserverForName:@"_UIApplicationSystemGestureStateChangedNotification"
object:nil
queue:nil
usingBlock:^(NSNotification *note) {
NSLog(@"Status bar pressed!");
}];
回答by swordray
Use an invisible UIScrollView
. Tested at iOS 10 & Swift 3.
使用隐形UIScrollView
. 在 iOS 10 和 Swift 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
}
回答by apb
If you're just trying to have a UIScrollView
scroll to the top when the status bar is tapped, it's worth noting that this is the default behavior IF your view controller has exactly one UIScrollView
in its subviews that has scrollsToTop
set to YES
.
如果您只是想在UIScrollView
点击状态栏时滚动到顶部,则值得注意的是,如果您的视图控制器UIScrollView
在其子视图中恰好有一个scrollsToTop
设置为YES
.
So I just had to go and find any other UIScrollView
(or subclasses: UITableView
, UICollectionView
, and set scrollsToTop
to be NO
.
所以我只需要去找任何其他UIScrollView
(或子类:UITableView
,UICollectionView
,并设置scrollsToTop
为NO
.
To be fair, I found this info in the post that was linked toin the original question, but it's also dismissed as no longer working so I skipped it and only found the relevant piece on a subsequent search.
公平地说,我在原始问题中链接到的帖子中找到了此信息,但它也因不再有效而被驳回,因此我跳过了它,仅在随后的搜索中找到了相关部分。
回答by Daniel
One way, might not be the best, could be to put a clear UIView on top of the status bar and intercept the touches of the UIView, might help you out if nothing else comes up...
一种方法,可能不是最好的,可能是在状态栏顶部放置一个清晰的 UIView 并拦截 UIView 的触摸,如果没有其他问题,可能会帮助你......