You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

为何tabBar.rx.didSelectItem未触发点击事件?如何修复?

问题分析与解决

问题现象

点击手动添加的TabBarItem“Bookmarks”时,控制台仅打印root view tapped,预期的select tabbar item未输出,且希望点击TabBar时不触发根视图的点击事件。

原因

  1. 手势识别冲突:根视图的UITapGestureRecognizer与UITabBar自身的点击手势识别器产生竞争,根视图的手势优先级更高,导致TabBar的点击事件被拦截,无法触发didSelectItem回调。
  2. 非标准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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.22 15:50:45