点击导航栏标题弹出Popover:无法隐藏箭头并准确定位的技术问题
解决导航栏标题触发Popover的定位问题
我之前也碰到过类似的场景——导航栏标题是自定义的图文组合,没法直接把它作为Popover的锚点视图,用透明按钮做锚点后,隐藏箭头就定位失效了。这里分享两个靠谱的解决方案:
方案一:优化透明锚点按钮的定位逻辑
问题的核心是隐藏箭头后,系统不再基于箭头方向自动调整Popover的偏移,所以需要精准控制sourceRect的位置。
步骤1:让透明按钮和导航栏标题精准对齐
不要只把按钮放在安全区顶部,而是让它和自定义标题视图的尺寸、位置完全匹配:
// 假设你的自定义标题视图是navigationItem.titleView guard let titleView = navigationItem.titleView else { return } // 创建透明按钮 let anchorButton = UIButton(type: .system) anchorButton.backgroundColor = .clear anchorButton.addTarget(self, action: #selector(showPopover), for: .touchUpInside) view.addSubview(anchorButton) // 用AutoLayout让按钮和标题视图完全对齐 anchorButton.translatesAutoresizingMaskIntoConstraints = false NSLayoutConstraint.activate([ anchorButton.centerXAnchor.constraint(equalTo: titleView.centerXAnchor), anchorButton.topAnchor.constraint(equalTo: view.safeAreaLayoutGuide.topAnchor), anchorButton.widthAnchor.constraint(equalTo: titleView.widthAnchor), anchorButton.heightAnchor.constraint(equalTo: titleView.heightAnchor) ])
步骤2:隐藏箭头时精准设置sourceRect
当隐藏箭头(permittedArrowDirections = [])时,把sourceRect的y值设为按钮的底部位置,让Popover的顶部刚好贴在导航栏下方:
@objc func showPopover() { let popoverVC = YourPopoverContentViewController() popoverVC.modalPresentationStyle = .popover guard let popoverPresenter = popoverVC.popoverPresentationController else { return } popoverPresenter.sourceView = anchorButton popoverPresenter.permittedArrowDirections = [] // 隐藏箭头 // 计算按钮在全局坐标系的底部位置 let buttonGlobalFrame = anchorButton.superview?.convert(anchorButton.frame, to: nil) ?? .zero // 设置sourceRect为按钮底部的中心点,让Popover从这里开始显示 popoverPresenter.sourceRect = CGRect( x: buttonGlobalFrame.midX, y: buttonGlobalFrame.maxY, width: 1, height: 1 ) present(popoverVC, animated: true) }
方案二:自定义导航栏标题视图作为锚点(更简洁)
其实我们可以直接把自定义的图文标题视图做成可点击的,省去额外的透明按钮:
步骤1:创建可交互的自定义标题视图
// 自定义标题视图容器 let customTitleView = UIView() customTitleView.isUserInteractionEnabled = true // 添加你的标签和图片到customTitleView let titleLabel = UILabel() titleLabel.text = "你的标题" let iconImageView = UIImageView(image: UIImage(systemName: "chevron.down")) // 布局标签和图片...(这里根据你的需求添加AutoLayout) customTitleView.addSubview(titleLabel) customTitleView.addSubview(iconImageView) // 添加点击手势 let tapGesture = UITapGestureRecognizer(target: self, action: #selector(showPopover)) customTitleView.addGestureRecognizer(tapGesture) // 设置为导航栏标题视图 navigationItem.titleView = customTitleView
步骤2:直接用标题视图作为Popover锚点
@objc func showPopover() { let popoverVC = YourPopoverContentViewController() popoverVC.modalPresentationStyle = .popover guard let popoverPresenter = popoverVC.popoverPresentationController, let titleView = navigationItem.titleView else { return } popoverPresenter.sourceView = titleView popoverPresenter.permittedArrowDirections = [] // 隐藏箭头 // 设置sourceRect为标题视图的底部区域,确保Popover定位正确 popoverPresenter.sourceRect = CGRect( x: titleView.bounds.midX, y: titleView.bounds.maxY, width: 1, height: 1 ) present(popoverVC, animated: true) }
这两种方案都能解决隐藏箭头后的定位问题,方案二更简洁,省去了额外的锚点按钮,推荐优先尝试。
内容的提问来源于stack exchange,提问作者SKT
相关产品推荐
相关产品推荐

