UINavigationBar右侧垂直排列UIBarButtonItem超出区域点击无响应问题
你的推测完全正确,iOS 默认情况下,视图只会响应落在自身 bounds 范围内的点击事件。你自定义的 rightBarButtonCustomView 高度为90,超出了 UINavigationBar 的默认高度范围,位于下方的通知按钮不在导航栏的可点击区域内,所以点击事件被系统拦截,无法传递到通知按钮。
以下是两种可行的解决方案:
方案1:重写UINavigationBar的点击检测方法(推荐)
自定义UINavigationBar子类,重写 hitTest(_:with:) 方法,手动判断点击位置是否落在自定义按钮区域,匹配后直接返回对应按钮响应事件:
class CustomNavigationBar: UINavigationBar { override func hitTest(_ point: CGPoint, with event: UIEvent?) -> UIView? { // 查找导航栏上的自定义右侧按钮容器视图 for subview in subviews { guard let customContainer = subview.subviews.first(where: { $0.frame.width == 40 && $0.frame.height == 90 }) else { continue } // 转换点击坐标到容器视图坐标系 let convertPoint = convert(point, to: customContainer) // 检测点击是否落在容器内,是则交给容器处理点击 if customContainer.bounds.contains(convertPoint) { return customContainer.hitTest(convertPoint, with: event) } } // 不匹配则走系统默认逻辑 return super.hitTest(point, with: event) } }
使用方式:初始化导航控制器时指定自定义导航栏类即可:
let navVC = UINavigationController( navigationBarClass: CustomNavigationBar.self, toolbarClass: nil ) navVC.viewControllers = [你的当前ViewController()]
方案2:重写当前ViewController的点击检测方法
如果不想全局修改导航栏,可直接在当前页面的ViewController中重写 hitTest 方法:
override func hitTest(_ point: CGPoint, with event: UIEvent?) -> UIView? { guard let customContainer = navigationItem.rightBarButtonItem?.customView else { return super.hitTest(point, with: event) } let convertPoint = view.convert(point, to: customContainer) if customContainer.bounds.contains(convertPoint) { return customContainer.hitTest(convertPoint, with: event) } return super.hitTest(point, with: event) }
优化建议
不要硬写布局数值匹配容器视图,可给自定义的 rightBarButtonCustomView 绑定唯一tag(比如 customContainer.tag = 999),判断时用tag匹配,后续修改布局时代码兼容性更强。
内容的提问来源于stack exchange,提问作者goatofanerd
相关产品推荐
相关产品推荐

