// // MainTabBarController.swift // suixinkan // import UIKit /// 主 Tab 容器,展示四个一级入口及中间扫码按钮。 final class MainTabBarController: UITabBarController { private let badgeViewModel = MainTabBadgeViewModel() private var tabNavigationControllers: [AppTab: TabNavigationController] = [:] private var isSyncingTabSelection = false /// 测试时可注入扫码点击处理。 var onScanTabSelected: (() -> Void)? private enum TabSlot: CaseIterable { case home case orders case scan case statistics case profile var appTab: AppTab? { switch self { case .home: return .home case .orders: return .orders case .scan: return nil case .statistics: return .statistics case .profile: return .profile } } static func index(for tab: AppTab) -> Int? { allCases.firstIndex { $0.appTab == tab } } static var scanIndex: Int? { allCases.firstIndex(of: .scan) } } override func viewDidLoad() { super.viewDidLoad() delegate = self configureTabBarAppearance() configureTabs() bindBadgeViewModel() badgeViewModel.refreshPendingWriteOffCount() } /// 选中指定主 Tab。 func selectTab(_ tab: AppTab) { guard let index = TabSlot.index(for: tab) else { return } guard selectedIndex != index else { return } isSyncingTabSelection = true selectedIndex = index isSyncingTabSelection = false if tab == .orders { badgeViewModel.refreshPendingWriteOffCount() } } private func configureTabBarAppearance() { tabBar.tintColor = AppColor.primary tabBar.backgroundColor = .white tabBar.shadowImage = UIImage() let normalAttributes: [NSAttributedString.Key: Any] = [ .foregroundColor: UIColor(hex: 0x7D8DA3), .font: UIFont.systemFont(ofSize: 12, weight: .regular), ] let selectedAttributes: [NSAttributedString.Key: Any] = [ .foregroundColor: AppColor.primary, .font: UIFont.systemFont(ofSize: 12, weight: .medium), ] let appearance = UITabBarAppearance() appearance.configureWithOpaqueBackground() appearance.backgroundColor = .white appearance.shadowColor = .clear appearance.stackedLayoutAppearance.normal.titleTextAttributes = normalAttributes appearance.stackedLayoutAppearance.selected.titleTextAttributes = selectedAttributes tabBar.standardAppearance = appearance tabBar.scrollEdgeAppearance = appearance } private func configureTabs() { tabNavigationControllers.removeAll() viewControllers = TabSlot.allCases.map { slot in if let tab = slot.appTab { let navigationController = TabNavigationController(tab: tab) navigationController.tabBarItem = tab.makeTabBarItem() tabNavigationControllers[tab] = navigationController return navigationController } let scannerPlaceholder = UIViewController() scannerPlaceholder.tabBarItem = MainScanTabItem.makeTabBarItem() return scannerPlaceholder } } private func bindBadgeViewModel() { badgeViewModel.onChange = { [weak self] in self?.updateOrderBadge() } } private func updateOrderBadge() { let badgeValue: String? if let count = badgeViewModel.pendingWriteOffCount, count > 0 { badgeValue = "\(count)" } else { badgeValue = nil } tabNavigationControllers[.orders]?.tabBarItem.badgeValue = badgeValue } private func presentGlobalScanner() { guard presentedViewController == nil else { return } let scanner = ScanPlaceholderViewController() let navigationController = UINavigationController(rootViewController: scanner) navigationController.modalPresentationStyle = .fullScreen present(navigationController, animated: true) } } extension MainTabBarController: UITabBarControllerDelegate { func tabBarController(_ tabBarController: UITabBarController, shouldSelect viewController: UIViewController) -> Bool { guard viewControllers?.firstIndex(of: viewController) == TabSlot.scanIndex else { return true } if let onScanTabSelected { onScanTabSelected() } else { presentGlobalScanner() } return false } func tabBarController(_ tabBarController: UITabBarController, didSelect viewController: UIViewController) { guard !isSyncingTabSelection, let navigationController = viewController as? TabNavigationController else { return } if navigationController.appTab == .orders { badgeViewModel.refreshPendingWriteOffCount() } } }