iOS隐藏状态栏后点击区域穿透到下层视图如何解决
解决隐藏状态栏后点击穿透及恢复滚动到顶部功能方案
核心原理
隐藏系统状态栏后,系统原本负责处理状态栏点击的响应区域失效,点击事件会直接透传给下层视图。我们可以在原状态栏对应位置添加一层透明的占位视图,既可以拦截点击事件避免穿透,又能自主实现点击滚动到顶部的逻辑。
具体实现步骤
- 在对应ViewController中添加占位视图,尺寸和原状态栏保持一致,放在视图层级最顶部
- 给占位视图添加点击手势,触发时控制UICollectionView滚动到顶部
代码示例
Swift 版本
// 声明占位视图属性 private let statusBarDummyView = UIView() override func viewDidLoad() { super.viewDidLoad() setupStatusBarDummyView() } private func setupStatusBarDummyView() { // 把占位视图加到最顶层,避免被其他子视图遮挡 view.addSubview(statusBarDummyView) view.bringSubviewToFront(statusBarDummyView) statusBarDummyView.backgroundColor = .clear statusBarDummyView.translatesAutoresizingMaskIntoConstraints = false // 适配不同系统版本获取状态栏高度 let statusBarHeight: CGFloat if #available(iOS 13.0, *) { statusBarHeight = view.window?.windowScene?.statusBarManager?.statusBarFrame.height ?? 20 } else { statusBarHeight = UIApplication.shared.statusBarFrame.height } // 配置布局约束 NSLayoutConstraint.activate([ statusBarDummyView.topAnchor.constraint(equalTo: view.topAnchor), statusBarDummyView.leadingAnchor.constraint(equalTo: view.leadingAnchor), statusBarDummyView.trailingAnchor.constraint(equalTo: view.trailingAnchor), statusBarDummyView.heightAnchor.constraint(equalToConstant: statusBarHeight) ]) // 添加点击手势 let tapGesture = UITapGestureRecognizer(target: self, action: #selector(statusBarTapAction)) statusBarDummyView.addGestureRecognizer(tapGesture) } // 点击事件处理,滚动到集合视图顶部 @objc private func statusBarTapAction() { // 方式1:滚动到第一个cell位置 let topIndexPath = IndexPath(item: 0, section: 0) collectionView.scrollToItem(at: topIndexPath, at: .top, animated: true) // 方式2:直接设置contentOffset,适合需要滚动到最顶部(包含sectionHeader的场景) // collectionView.setContentOffset(CGPoint(x: 0, y: -collectionView.adjustedContentInset.top), animated: true) }
Objective-C 版本
// .h文件或类扩展中声明属性 @property (nonatomic, strong) UIView *statusBarDummyView; @implementation YourViewController - (void)viewDidLoad { [super viewDidLoad]; [self setupStatusBarDummyView]; } - (void)setupStatusBarDummyView { self.statusBarDummyView = [[UIView alloc] init]; self.statusBarDummyView.backgroundColor = [UIColor clearColor]; self.statusBarDummyView.translatesAutoresizingMaskIntoConstraints = NO; [self.view addSubview:self.statusBarDummyView]; [self.view bringSubviewToFront:self.statusBarDummyView]; CGFloat statusBarHeight = 0; if (@available(iOS 13.0, *)) { statusBarHeight = self.view.window.windowScene.statusBarManager.statusBarFrame.size.height ?: 20; } else { statusBarHeight = [UIApplication sharedApplication].statusBarFrame.size.height; } [NSLayoutConstraint activateConstraints:@[ self.statusBarDummyView.topAnchor.constraintEqualToAnchor:self.view.topAnchor, self.statusBarDummyView.leadingAnchor.constraintEqualToAnchor:self.view.leadingAnchor, self.statusBarDummyView.trailingAnchor.constraintEqualToAnchor:self.view.trailingAnchor, self.statusBarDummyView.heightAnchor.constraintEqualToConstant:statusBarHeight ]]; UITapGestureRecognizer *tapGesture = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(statusBarTapAction)]; [self.statusBarDummyView addGestureRecognizer:tapGesture]; } - (void)statusBarTapAction { // 方式1:滚动到第一个cell NSIndexPath *topIndexPath = [NSIndexPath indexPathForItem:0 inSection:0]; [self.collectionView scrollToItemAtIndexPath:topIndexPath atScrollPosition:UICollectionViewScrollPositionTop animated:YES]; // 方式2:直接设置contentOffset // [self.collectionView setContentOffset:CGPointMake(0, -self.collectionView.adjustedContentInset.top) animated:YES]; } @end
适配注意事项
- 如果页面支持横竖屏切换,需要在
viewWillLayoutSubviews或traitCollectionDidChange回调中更新占位视图的高度约束,适配横竖屏下不同的状态栏高度 - 如果页面存在多个可滚动视图,在点击事件中指定需要滚动到顶部的目标视图即可
- 确保占位视图始终在视图层级的最顶部,不会被其他自定义导航栏、悬浮视图遮挡影响点击响应
内容的提问来源于stack exchange,提问作者user626776
相关产品推荐
相关产品推荐

