navigationItem.hidesBackButton

本文探讨了在iOS应用中遇到的一个问题:在某些情况下self.navigationItem.hidesBackButton=NO设置后,backButton在真实设备上不显示的问题。文章详细解释了这一现象的原因,并给出了解决方案,特别是关于rightBarButtonItem的存在及其移除时机对于backButton显示的影响。
self.navigationItem.hidesBackButton = NO, 有时候会没有效果,在调用上面这条语句后,backButton并没有如预期一样出现,在模拟器上并没有问题,只是真机上才会出现,我用的是3GS 4.2.1。如果你加入了一个rightBarButtonItem,并且你会在页面运行中取消使用,即self.navigationItem.rightBarButtonItem = nil; 如果你在self.navigationItem.hidesBackButton = NO 语句后移除rightBarButtonItem,backButton就会在第二次pushViewController后,并且调用self.navigationItem.hidesBackButton = NO后,backButton不会出现,如果先于self.navigationItem.hidesBackButton = NO 调用 self.navigationItem.rightBarButtonItem = nil; 就不会有这个bug出现。
讲一下这段逻辑 private func updateNavigationBarButtons() { if !appContext.isLogin { //未登录 if showLocalDeviceOnly { if localDeviceCount == 0 { self.navigationItem.rightBarButtonItems = [addButtonmItem] } else { self.navigationItem.rightBarButtonItems = [addButtonmItem, negativeButtonItem] } moreSiteButton.isHidden = localDeviceCount == 0 tabBarCollectionView.isHidden = localDeviceCount == 0 } else { //如果未登录则左边按钮不显示 self.navigationItem.leftBarButtonItems = [mineButtonItem] //右边显示所有按钮 self.navigationItem.rightBarButtonItems = [addButtonmItem,negativeButtonItem] tabBarCollectionView.isHidden = true } scrollView.setContentOffset(CGPoint(x: 0, y: 62), animated: false) } else { //如果登录了则左边按钮显示 if showLocalDeviceOnly { moreSiteButton.isHidden = localDeviceCount == 0 tabBarCollectionView.isHidden = localDeviceCount == 0 if localDeviceCount == 0 { self.navigationItem.rightBarButtonItems = [addButtonmItem] } else { self.navigationItem.rightBarButtonItems = [addButtonmItem, negativeButtonItem, searchItem] } removeLeftBarButtonItem() addCustomNavigationLeftBarButtonItem(title: nil, image: TPImageLiteral("common_light_back_nor")) } else { moreSiteButton.isHidden = false tabBarCollectionView.isHidden = false if appContext.isVmsLogin { // 登录状态VMS if isDeviceListOld { removeLeftBarButtonItem() addCustomNavigationLeftBarButtonItem(title: nil, image: TPImageLiteral("common_light_back_nor")) self.navigationItem.rightBarButtonItems = [searchItem, changeDisplayTypeItem] } else { // tab新版VMS不能滚动 tabBarCollectionView.isScrollEnabled = true // addLeftBarButtonItem() if appContext.loginType == .cloud { self.navigationItem.rightBarButtonItems = [addButtonmItem, negativeButtonItem] } else { self.navigationItem.rightBarButtonItems = [] } } } else { // 登录状态个人版 reqVmsOrgListCode = appContext.requestVMSOrganizationList(withUsername: appContext.accountUsername, password: appContext.accountPassword ?? "") // removeLeftBarButtonItem() // if let hasVms = UserDefaults.standard.object(forKey: kHasCloudVMSOrganization) as? Bool, hasVms { // addLeftBarButtonItem() // } self.navigationItem.rightBarButtonItems = [addButtonmItem, negativeButtonItem] } } scrollView.setContentOffset(CGPoint(x: 0, y: 62), animated: false) } }
最新发布
11-28
你提供的这段代码: ```swift private func updateNavigationBarButtons() ``` 是一个 **根据用户登录状态、设备类型和界面布局动态配置导航栏按钮** 的核心逻辑函数。它控制了 `UINavigationItem` 的左右两侧按钮显示与隐藏,同时影响页面其他 UI 元素(如 `tabBarCollectionView`、`moreSiteButton` 和 `scrollView` 偏移)。 --- ## 🧠 总体结构解析 该方法通过嵌套条件判断,根据不同场景组合出不同的导航栏按钮配置。整体流程如下: ``` if !appContext.isLogin → 未登录 │ ├── showLocalDeviceOnly == true │ ├── localDeviceCount == 0 → 只显示添加按钮 │ └── localDeviceCount > 0 → 显示添加 + 负间距 │ └── showLocalDeviceOnly == false ├── 左侧显示 "我的" 按钮 ├── 右侧显示 添加 + 负间距 └── 隐藏 tabBar else → 已登录 │ ├── showLocalDeviceOnly == true │ ├── 根据 localDeviceCount 决定是否显示右侧按钮 │ ├── 隐藏左侧系统返回按钮 │ └── 自定义左侧返回图标 │ └── showLocalDeviceOnly == false ├── VMS 登录? │ ├── 是旧版设备列表 → 显示搜索 + 切换视图模式 │ └── 是新版 → 根据 cloud 登录类型决定是否显示添加按钮 │ └── 个人版登录 → 请求组织信息,显示添加按钮 ``` --- ## 🔍 逐段详解 + 中文注释版 ```swift private func updateNavigationBarButtons() { if !appContext.isLogin { // 👇 用户未登录 if showLocalDeviceOnly { // 场景:仅查看本地设备(比如刚打开 App 尚未登录) if localDeviceCount == 0 { // 没有本地设备 → 只保留“添加”按钮 self.navigationItem.rightBarButtonItems = [addButtonmItem] } else { // 有本地设备 → 显示“添加”按钮 + 负间距微调位置 self.navigationItem.rightBarButtonItems = [addButtonmItem, negativeButtonItem] } // 更多站点按钮 & tab 条:无设备时隐藏 moreSiteButton.isHidden = localDeviceCount == 0 tabBarCollectionView.isHidden = localDeviceCount == 0 } else { // 未登录但不只看本地设备(可能在选择服务器?) // 左侧显示“我的”入口 self.navigationItem.leftBarButtonItems = [mineButtonItem] // 右侧仍显示添加按钮 + 负间距 self.navigationItem.rightBarButtonItems = [addButtonmItem, negativeButtonItem] // 隐藏下方的 tab 列表 tabBarCollectionView.isHidden = true } // 设置 scrollView 初始偏移(避开导航栏下方内容) scrollView.setContentOffset(CGPoint(x: 0, y: 62), animated: false) } else { // 👇 用户已登录 if showLocalDeviceOnly { // 当前只展示本地设备 moreSiteButton.isHidden = localDeviceCount == 0 tabBarCollectionView.isHidden = localDeviceCount == 0 if localDeviceCount == 0 { // 无设备 → 只显示添加按钮 self.navigationItem.rightBarButtonItems = [addButtonmItem] } else { // 有设备 → 添加按钮 + 负间距 + 搜索按钮 self.navigationItem.rightBarButtonItems = [addButtonmItem, negativeButtonItem, searchItem] } // 移除默认的左侧返回按钮(避免重复) removeLeftBarButtonItem() // 添加自定义返回按钮(带特定图标) addCustomNavigationLeftBarButtonItem(title: nil, image: TPImageLiteral("common_light_back_nor")) } else { // 不是只看本地设备 → 展示完整设备列表(VMS 或云服务) moreSiteButton.isHidden = false tabBarCollectionView.isHidden = false if appContext.isVmsLogin { // 👇 VMS 登录(企业级视频管理系统) if isDeviceListOld { // 使用旧版设备列表 UI removeLeftBarButtonItem() addCustomNavigationLeftBarButtonItem(title: nil, image: TPImageLiteral("common_light_back_nor")) // 右侧显示:搜索 + 切换显示模式(如网格/列表) self.navigationItem.rightBarButtonItems = [searchItem, changeDisplayTypeItem] } else { // 新版 UI:支持滚动的 Tab tabBarCollectionView.isScrollEnabled = true // 如果是云账号登录 → 显示添加按钮 if appContext.loginType == .cloud { self.navigationItem.rightBarButtonItems = [addButtonmItem, negativeButtonItem] } else { // 非云账号 → 不显示任何右侧按钮 self.navigationItem.rightBarButtonItems = [] } } } else { // 👇 个人版登录(非 VMS,可能是普通账户) // 请求 VMS 组织列表(用于后续权限判断) reqVmsOrgListCode = appContext.requestVMSOrganizationList( withUsername: appContext.accountUsername, password: appContext.accountPassword ?? "" ) // 准备左侧按钮(被注释掉了,说明暂时不用) // removeLeftBarButtonItem() // if let hasVms = UserDefaults.standard.object(forKey: kHasCloudVMSOrganization) as? Bool, hasVms { // addLeftBarButtonItem() // } // 右侧显示添加按钮 + 负间距 self.navigationItem.rightBarButtonItems = [addButtonmItem, negativeButtonItem] } } // 登录状态下也设置初始偏移 scrollView.setContentOffset(CGPoint(x: 0, y: 62), animated: false) } } ``` --- ## ✅ 关键设计意图总结 | 场景 | 设计目的 | |------|----------| | **未登录 + 无本地设备** | 引导用户点击“+”添加设备 | | **未登录 + 有本地设备** | 提供基础操作入口,隐藏复杂功能 | | **登录后 + 本地模式** | 支持搜索 + 添加,提升可用性 | | **VMS 旧版列表** | 突出搜索和切换视图方式,适合监控场景 | | **VMS 新版 + 非云账号** | 隐藏添加按钮 → 表示不可编辑 | | **个人版登录** | 允许添加设备,体现自由度 | --- ## ⚠️ 存在的问题或可优化点 ### 1. **命名错误:`addButtonmItem` 应为 `addButtonItem`** ```swift self.navigationItem.rightBarButtonItems = [addButtonmItem] // ❌ 多了一个 m ``` 这很可能是笔误,建议立即修正为: ```swift self.navigationItem.rightBarButtonItems = [addButtonItem] ``` ### 2. **部分代码被注释掉(技术债)** ```swift // removeLeftBarButtonItem() // if let hasVms = ... { addLeftBarButtonItem() } ``` 这些注释代码会让新人困惑,应: - 删除不用的 - 或加上注释说明原因 ### 3. **重复设置 `setContentOffset`** 两处都有: ```swift scrollView.setContentOffset(CGPoint(x: 0, y: 62), animated: false) ``` 可以提取到末尾统一执行。 ### 4. **缺乏状态枚举管理,逻辑过于分散** 建议引入状态机或枚举来简化判断: ```swift enum DeviceListViewState { case notLoggedIn(localOnly: Bool, deviceCount: Int) case loggedInPersonal(hasVms: Bool) case loggedInVms(isOldVersion: Bool, isCloud: Bool) } ``` 然后用 `switch state` 替代多重 `if-else`。 --- ## ✅ 如何测试这个方法? 你可以写一个测试用例模拟不同状态: ```swift func testUpdateNavigationBarButtons_notLoggedIn_localOnly_noDevices() { sut.appContext.isLogin = false sut.showLocalDeviceOnly = true sut.localDeviceCount = 0 sut.updateNavigationBarButtons() XCTAssertEqual(sut.navigationItem.rightBarButtonItems?.count, 1) XCTAssertNil(sut.navigationItem.leftBarButtonItems) XCTAssertTrue(sut.moreSiteButton.isHidden) XCTAssertTrue(sut.tabBarCollectionView.isHidden) } ``` ---
评论 1
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值