如何将自定义按钮与导航栏右侧UIBarButtonItem对齐?
这个问题我之前做项目时也踩过坑——UIBarButtonItem确实不是UIView的子类,没法直接给它加Auto Layout约束,不过咱们有两种靠谱的解决思路,根据你的需求选就行:
方法一:自定义导航栏右侧按钮(推荐)
既然系统自带的UIBarButtonSystemItem.edit没法直接用来做约束参照,咱们可以自己创建一个UIButton,把它包装成UIBarButtonItem,这样就能直接用这个按钮来对齐下方的视图了,而且样式完全可以和系统Edit按钮保持一致。
代码实现:
首先在你的ViewController里定义两个属性:
private var customEditButton: UIButton! private var bottomAlignButton: UIButton!
然后在viewDidLoad里设置导航栏和下方按钮:
override func viewDidLoad() { super.viewDidLoad() // 1. 创建自定义Edit按钮,匹配系统样式 customEditButton = UIButton(type: .system) customEditButton.setTitle("Edit", for: .normal) // 系统Edit按钮的字体是半粗体,字号17,这里对齐样式 customEditButton.titleLabel?.font = UIFont.systemFont(ofSize: 17, weight: .semibold) customEditButton.addTarget(self, action: #selector(editButtonTapped), for: .touchUpInside) customEditButton.sizeToFit() // 2. 把自定义按钮包装成UIBarButtonItem,设置为导航栏右侧项 let editBarButtonItem = UIBarButtonItem(customView: customEditButton) navigationItem.rightBarButtonItem = editBarButtonItem // 3. 创建下方需要对齐的按钮 bottomAlignButton = UIButton(type: .system) bottomAlignButton.setTitle("对齐按钮", for: .normal) bottomAlignButton.translatesAutoresizingMaskIntoConstraints = false view.addSubview(bottomAlignButton) // 4. 直接用customEditButton设置约束,完美对齐 NSLayoutConstraint.activate([ bottomAlignButton.topAnchor.constraint(equalTo: navigationController!.navigationBar.bottomAnchor, constant: 20), // 关键:让下方按钮的右边缘和自定义Edit按钮的右边缘对齐 bottomAlignButton.trailingAnchor.constraint(equalTo: customEditButton.trailingAnchor), bottomAlignButton.heightAnchor.constraint(equalToConstant: 44) ]) } // 处理Edit按钮的点击事件 @objc private func editButtonTapped() { // 这里写你的编辑逻辑 }
这种方法的好处是完全不用依赖私有API,约束是一次性设置的,不管屏幕旋转还是导航栏布局变化,下方按钮都会自动跟着对齐,非常稳定。
方法二:获取系统按钮的视图来对齐
如果你不想自定义按钮,非要用系统自带的UIBarButtonSystemItem.edit,那可以通过一些方式拿到它对应的实际UIView,再用这个视图的位置来更新下方按钮的约束。
代码实现:
同样先定义属性:
private var editBarButtonItem: UIBarButtonItem! private var bottomAlignButton: UIButton! private var trailingConstraint: NSLayoutConstraint? // 保存trailing约束,方便更新
在viewDidLoad里初始化:
override func viewDidLoad() { super.viewDidLoad() // 设置系统Edit按钮为导航栏右侧项 editBarButtonItem = UIBarButtonItem(barButtonSystemItem: .edit, target: self, action: #selector(editButtonTapped)) navigationItem.rightBarButtonItem = editBarButtonItem // 创建下方对齐按钮 bottomAlignButton = UIButton(type: .system) bottomAlignButton.setTitle("对齐按钮", for: .normal) bottomAlignButton.translatesAutoresizingMaskIntoConstraints = false view.addSubview(bottomAlignButton) // 设置基本约束:距离导航栏下方20,高度44 NSLayoutConstraint.activate([ bottomAlignButton.topAnchor.constraint(equalTo: navigationController!.navigationBar.bottomAnchor, constant: 20), bottomAlignButton.heightAnchor.constraint(equalToConstant: 44) ]) } @objc private func editButtonTapped() { // 编辑逻辑 }
然后在viewDidLayoutSubviews里更新对齐约束(这个方法会在布局变化时被调用,比如屏幕旋转):
override func viewDidLayoutSubviews() { super.viewDidLayoutSubviews() // 通过value(forKey:)获取系统按钮对应的UIView(注意:这是利用了UIKit的私有属性,虽然实际开发中很少被拒,但有一定风险) guard let editButtonView = editBarButtonItem.value(forKey: "view") as? UIView else { return } // 把系统按钮的frame转换到当前ViewController的view坐标系里 let editButtonFrameInView = view.convert(editButtonView.frame, from: editButtonView.superview) // 先移除之前的trailing约束,避免重复添加 trailingConstraint?.isActive = false // 创建新的trailing约束:让下方按钮的右边缘和系统Edit按钮的右边缘对齐 trailingConstraint = bottomAlignButton.trailingAnchor.constraint(equalTo: view.trailingAnchor, constant: -(view.bounds.width - editButtonFrameInView.maxX)) trailingConstraint?.isActive = true }
这种方法的缺点是依赖了UIKit的私有属性,虽然目前能用,但如果苹果后续修改了UIBarButtonItem的内部实现,可能会失效,所以更推荐第一种自定义按钮的方式。
内容的提问来源于stack exchange,提问作者nambatee
相关产品推荐
相关产品推荐

