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

如何将自定义按钮与导航栏右侧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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.15 08:23:51