UIBarButtonItem字体粗细变化时如何固定其尺寸避免晃动?
问题说明
UIBarButtonItem切换字体粗细时会根据文本属性自动计算宽度,导致按钮整体偏移晃动,效果如下:
解决方案
核心思路是固定UIBarButtonItem的宽度,不再随文本属性动态调整,推荐使用自定义customView的方案,兼容性最高、实现简单:
- 创建UIBarButtonItem时封装固定宽度的UIButton作为customView,宽度按照粗体文本的最大宽度预留,避免切换时空间不足
- 高亮逻辑调整为修改customView内UIButton的文本属性
修改后的完整可运行代码如下:
import UIKit class ViewController: UIViewController { var barButtonItems: [UIBarButtonItem]! override func viewDidLoad() { super.viewDidLoad() view.backgroundColor = .darkGray let navBar: UINavigationBar = UINavigationBar(frame: CGRect(x: 0, y: 100, width: view.frame.width, height: 40)) navBar.barTintColor = #colorLiteral(red: 0.1019607857, green: 0.2784313858, blue: 0.400000006, alpha: 1) view.addSubview(navBar) let navItem = UINavigationItem() // 改为创建自定义按钮封装成UIBarButtonItem let appleBarBtnItem = createCustomBarBtn(title: "Apple", tag: 0) let bananaBarBtnItem = createCustomBarBtn(title: "Banana", tag: 1) let kiwiBarBtnItem = createCustomBarBtn(title: "Kiwi", tag: 2) let pearBarBtnItem = createCustomBarBtn(title: "Pear", tag: 3) let orangeBarBtnItem = createCustomBarBtn(title: "Orange", tag: 4) barButtonItems = [appleBarBtnItem, bananaBarBtnItem, kiwiBarBtnItem, pearBarBtnItem, orangeBarBtnItem] navItem.leftBarButtonItems = barButtonItems navBar.setItems([navItem], animated: false) setCurrentBarItem(appleBarBtnItem) } // 新增:创建固定宽度的自定义UIBarButtonItem func createCustomBarBtn(title: String, tag: Int) -> UIBarButtonItem { // 提前计算该标题用粗体显示时的宽度,加20作为左右内边距,也可以直接写固定值如80 let boldFont = UIFont.systemFont(ofSize: 20, weight: .bold) let textWidth = title.size(withAttributes: [.font: boldFont]).width + 20 let button = UIButton(frame: CGRect(x: 0, y: 0, width: textWidth, height: 30)) button.setTitle(title, for: .normal) button.tag = tag button.addTarget(self, action: #selector(barItemTapped), for: .touchUpInside) return UIBarButtonItem(customView: button) } func setCurrentBarItem(_ barBtnItem: UIBarButtonItem) { for btn in barButtonItems { highlight(btn, turnedOn: (btn == barBtnItem) ) } } func highlight(_ button: UIBarButtonItem, turnedOn: Bool) { button.tintColor = #colorLiteral(red: 0.7230747342, green: 0.9554787278, blue: 0.9893732667, alpha: 1) let weight: UIFont.Weight = turnedOn ? .bold : .thin let attributes: [NSAttributedString.Key : Any] = [ .font: UIFont.systemFont(ofSize: 20, weight: weight)] // 改为修改customView中按钮的文本属性 guard let customBtn = button.customView as? UIButton else { return } customBtn.setTitleTextAttributes(attributes, for: .normal) } @objc func barItemTapped(_ sender: UIButton) { let targetItem = barButtonItems[sender.tag] setCurrentBarItem(targetItem) } }
如果不想使用自定义View,也可以在调用setTitleTextAttributes时,给所有状态的文本添加固定字间距,确保粗细切换时总宽度不变,但该方案适配不同文本长度的成本更高,更推荐上述自定义方案。
内容的提问来源于stack exchange,提问作者Kaplan
相关产品推荐
相关产品推荐

