为何tabBar.rx.didSelectItem未触发点击事件?如何修复?
问题分析与解决
问题现象
点击手动添加的TabBarItem“Bookmarks”时,控制台仅打印root view tapped,预期的select tabbar item未输出,且希望点击TabBar时不触发根视图的点击事件。
原因
- 手势识别冲突:根视图的
UITapGestureRecognizer与UITabBar自身的点击手势识别器产生竞争,根视图的手势优先级更高,导致TabBar的点击事件被拦截,无法触发didSelectItem回调。 - 非标准TabBar使用方式:将UITabBar直接添加到普通
UIViewController的视图层级中,而非使用苹果推荐的UITabBarController管理,TabBar的部分交互逻辑依赖于UITabBarController的生命周期与事件分发机制,手动添加可能导致事件传递异常。
修复方法
方法一:调整手势识别优先级,避免根视图手势拦截TabBar事件
在根视图的手势配置中,设置其需等待TabBar的点击手势识别失败后才响应:
// 根视图手势部分修改 let rootTapGesture = view.rx.tapGesture(configuration: { tapGestureRecognizer, delegate in delegate.simultaneousRecognitionPolicy = .never }) .when(.recognized) .subscribe(onNext: { ele in print("root view tapped ") }) .disposed(by: disposeBag) // 让根视图手势等待TabBar的点击手势失败后再触发 if let tabBarTapGesture = tabBar.gestureRecognizers?.first(where: { $0 is UITapGestureRecognizer }) { rootTapGesture.require(toFail: tabBarTapGesture) }
方法二:改用UITabBarController管理TabBar(推荐)
这是苹果官方推荐的TabBar使用方式,能从根源避免手动添加带来的交互问题:
import UIKit import RxSwift import RxCocoa class TabBarViewController: UITabBarController { private let disposeBag = DisposeBag() override func viewDidLoad() { super.viewDidLoad() // 创建子视图控制器并绑定TabBarItem let bookmarksVC = UIViewController() bookmarksVC.tabBarItem = UITabBarItem(tabBarSystemItem: .bookmarks, tag: 1) let contactsVC = UIViewController() contactsVC.tabBarItem = UITabBarItem(tabBarSystemItem: .contacts, tag: 2) self.viewControllers = [bookmarksVC, contactsVC] // 监听TabBarItem点击 self.tabBar.rx.didSelectItem.subscribe(onNext: { _ in print("select tabbar item ") }) .disposed(by: disposeBag) // 创建红色视图 let redView = UIView() redView.backgroundColor = .red self.view.addSubview(redView) redView.translatesAutoresizingMaskIntoConstraints = false NSLayoutConstraint.activate([ redView.leftAnchor.constraint(equalTo: self.view.leftAnchor), redView.rightAnchor.constraint(equalTo: self.view.rightAnchor), redView.bottomAnchor.constraint(equalTo: self.tabBar.topAnchor), redView.heightAnchor.constraint(equalTo: self.tabBar.heightAnchor) ]) // 红色视图点击监听 redView.rx.tapGesture() .when(.recognized) .subscribe { _ in print("red tapped") } .disposed(by: disposeBag) // 根视图点击监听(添加TabBar手势优先级判断) self.view.rx.tapGesture(configuration: { tapGesture, delegate in delegate.simultaneousRecognitionPolicy = .never if let tabBarTap = self.tabBar.gestureRecognizers?.first(where: { $0 is UITapGestureRecognizer }) { tapGesture.require(toFail: tabBarTap) } }) .when(.recognized) .subscribe { _ in print("root view tapped ") } .disposed(by: disposeBag) } }
方法三:手动过滤根视图手势的TabBar区域点击
如果必须使用手动添加TabBar的方式,可以在根视图的点击回调中判断触摸位置是否在TabBar范围内,若在则跳过响应:
// 根视图手势回调修改 view.rx.tapGesture(configuration: { tapGestureRecognizer, delegate in delegate.simultaneousRecognitionPolicy = .never }) .when(.recognized) .subscribe(onNext: { gesture in guard let touchLocation = gesture.location(in: self.view) else { return } // 判断触摸点是否不在TabBar范围内 if !self.tabBar.frame.contains(touchLocation) { print("root view tapped ") } }) .disposed(by: disposeBag)
内容的提问来源于stack exchange,提问作者Amy Microgoo
相关产品推荐
相关产品推荐

