iOS开发:复刻Health App导航栏标题旁用户账户按钮效果的高效实现方案
解决大标题导航栏中右侧按钮与标题同排的问题
这个问题其实是系统大标题导航栏的默认布局导致的:当你开启prefersLargeTitles = true时,导航栏会自动分成上下两个区域——上方放置操作按钮,下方显示大标题,所以你的用户按钮会被推到标题上方。
要复刻Health App的效果(按钮与大标题水平对齐),又不想硬编码静态常量,最简洁高效的方法是动态计算按钮的图片内边距,基于导航栏的实际高度和大标题字体的行高来调整按钮位置,完全适配不同设备和系统字体设置:
修改后的代码
import Foundation import UIKit class MyTabController : UITabBarController { override func viewDidLoad() { view.backgroundColor = .lightGray viewControllers = [createNavController(for: UIViewController(), title: NSLocalizedString("Summary", comment: ""), image: UIImage(systemName: "suit.heart.fill")!)] } internal func createNavController(for rootViewController: UIViewController, title: String, image: UIImage) -> UIViewController { let navController = UINavigationController(rootViewController: rootViewController) navController.tabBarItem.title = title navController.tabBarItem.image = image navController.navigationBar.prefersLargeTitles = true rootViewController.title = title // 创建用户按钮 let barButton = UIBarButtonItem(image: UIImage(systemName: "person.circle"), style: .plain, target: nil, action: nil) // 动态计算内边距,让按钮与大标题对齐 let largeTitleFont = UIFont.preferredFont(forTextStyle: .largeTitle) let largeTitleLineHeight = largeTitleFont.lineHeight let navBarHeight = navController.navigationBar.frame.height // 计算顶部内边距,让按钮垂直居中于大标题区域 let topInset = (navBarHeight - largeTitleLineHeight) / 2 barButton.imageInsets = UIEdgeInsets(top: topInset, left: 0, bottom: 0, right: 0) rootViewController.navigationItem.rightBarButtonItem = barButton return navController } }
原理说明
- 我们通过
UIFont.preferredFont(forTextStyle: .largeTitle)获取系统当前的大标题字体,确保适配用户的字体大小设置; - 用导航栏的实际高度减去大标题的行高,再除以2,得到需要向下偏移的距离;
- 将这个偏移量设置为按钮的图片顶部内边距,就能让按钮垂直居中于大标题所在的区域,实现和Health App一样的布局效果。
备选方案(自定义TitleView)
如果你需要更灵活的布局(比如标题和按钮之间的间距自定义),可以用UIStackView作为导航栏的titleView,把标题标签和用户按钮放在同一行:
internal func createNavController(for rootViewController: UIViewController, title: String, image: UIImage) -> UIViewController { let navController = UINavigationController(rootViewController: rootViewController) navController.tabBarItem.title = title navController.tabBarItem.image = image navController.navigationBar.prefersLargeTitles = true // 标题标签 let titleLabel = UILabel() titleLabel.text = title titleLabel.font = UIFont.preferredFont(forTextStyle: .largeTitle) titleLabel.adjustsFontForContentSizeCategory = true // 用户按钮 let userButton = UIButton(type: .system) userButton.setImage(UIImage(systemName: "person.circle"), for: .normal) userButton.frame = CGRect(x: 0, y: 0, width: 44, height: 44) // 匹配系统按钮尺寸 // 横向StackView组合标题和按钮 let titleStack = UIStackView(arrangedSubviews: [titleLabel, userButton]) titleStack.axis = .horizontal titleStack.alignment = .center titleStack.spacing = 8 rootViewController.navigationItem.titleView = titleStack return navController }
这个方案的好处是完全自定义布局,但需要自己处理滚动时大标题缩小的逻辑(如果需要的话)。
内容的提问来源于stack exchange,提问作者angryip
相关产品推荐
相关产品推荐

