# TabBar 结构改动指南 ## 📋 当前 TabBar 结构分析 基于 `TabbarViewController.h/m` 的分析,当前项目的 TabBar 包含以下模块: ### 现有结构(推测) 1. **首页** (Home) - `YMNewHome` 2. **消息** (Message) - `YMMessage` 3. **动态** (Moments) - `YMMonents` 4. **我的** (Mine) - `YMMine` 可能还有一个中间的"发布"按钮(常见于直播/社交应用)。 --- ## 🎯 改造目标 通过调整 TabBar 的结构、顺序、样式,让 App 在使用体验和视觉上都和原项目有明显区别。 --- ## 🔄 改造方案 ### 方案A: 改变顺序 **原顺序**:首页 → 消息 → [发布] → 动态 → 我的 **新顺序**:动态 → 首页 → [发布] → 我的 → 消息 **代码修改**: ```objc // TabbarViewController.m - (void)viewDidLoad { [super viewDidLoad]; // 创建各个 ViewController(顺序改变) NSArray *viewControllers = @[ [self createMomentsVC], // 动态(原本第3个,现在第1个) [self createHomeVC], // 首页(原本第1个,现在第2个) [self createBlankVC], // 占位(发布按钮) [self createMineVC], // 我的(原本第4个,现在第4个) [self createMessageVC] // 消息(原本第2个,现在第5个) ]; self.viewControllers = viewControllers; } ``` --- ### 方案B: 改变数量(5个→4个) 移除"动态"Tab,将其整合到首页或消息中。 **新结构**:首页 → 消息 → 我的 → 设置 ```objc - (void)viewDidLoad { [super viewDidLoad]; NSArray *viewControllers = @[ [self createHomeVC], // 首页 [self createMessageVC], // 消息 [self createMineVC], // 我的 [self createSettingsVC] // 新增:设置 ]; self.viewControllers = viewControllers; // 移除中间的凸起按钮 // self.customTabBar = nil; } ``` --- ### 方案C: 完全重新设计(4个→6个) 增加更多功能入口,显得是不同的产品定位。 **新结构**:发现 → 直播 → 短视频 → 消息 → 商城 → 我的 ```objc - (void)viewDidLoad { [super viewDidLoad]; NSArray *viewControllers = @[ [self createDiscoverVC], // 发现(重组的首页) [self createLiveVC], // 直播(原首页的一部分) [self createVideoVC], // 短视频(新增或从动态拆分) [self createMessageVC], // 消息 [self createShopVC], // 商城(新增或从我的拆分) [self createMineVC] // 我的 ]; self.viewControllers = viewControllers; } ``` --- ## 🎨 视觉改造 ### 1. TabBar 样式改变 #### 方案1: 平面风格 → 卡片风格 ```objc // TabbarViewController.m - (void)setupTabBarAppearance { // 创建卡片样式的 TabBar self.tabBar.backgroundColor = [UIColor whiteColor]; self.tabBar.layer.shadowColor = [UIColor blackColor].CGColor; self.tabBar.layer.shadowOffset = CGSizeMake(0, -3); self.tabBar.layer.shadowOpacity = 0.1; self.tabBar.layer.shadowRadius = 10; // 圆角 self.tabBar.layer.cornerRadius = 20; self.tabBar.layer.maskedCorners = kCALayerMinXMinYCorner | kCALayerMaxXMinYCorner; // 内边距 self.tabBar.frame = CGRectMake(0, self.tabBar.frame.origin.y, self.tabBar.frame.size.width, self.tabBar.frame.size.height + 20); } ``` #### 方案2: 固定底部 → 浮动底部 ```objc - (void)setupFloatingTabBar { // 让 TabBar 浮动在内容之上 self.tabBar.backgroundColor = [UIColor clearColor]; self.tabBar.backgroundImage = [UIImage new]; self.tabBar.shadowImage = [UIImage new]; // 创建自定义背景 UIView *customTabBar = [[UIView alloc] initWithFrame:CGRectMake(20, -10, self.tabBar.bounds.size.width - 40, self.tabBar.bounds.size.height - 10)]; customTabBar.backgroundColor = [UIColor whiteColor]; customTabBar.layer.cornerRadius = 25; customTabBar.layer.shadowColor = [UIColor blackColor].CGColor; customTabBar.layer.shadowOffset = CGSizeMake(0, -2); customTabBar.layer.shadowOpacity = 0.15; customTabBar.layer.shadowRadius = 15; [self.tabBar insertSubview:customTabBar atIndex:0]; } ``` --- ### 2. 选中动画改变 #### 方案1: 缩放动画 ```objc // XPTabBar.m (或新的 TabBar 类) - (void)setSelectedItem:(UITabBarItem *)selectedItem { [super setSelectedItem:selectedItem]; // 找到对应的按钮 NSInteger index = [self.items indexOfObject:selectedItem]; if (index != NSNotFound) { UIView *tabBarButton = self.subviews[index + 1]; // +1 是因为第一个是背景 // 缩放动画 [UIView animateWithDuration:0.3 delay:0 usingSpringWithDamping:0.5 initialSpringVelocity:0.5 options:UIViewAnimationOptionCurveEaseInOut animations:^{ tabBarButton.transform = CGAffineTransformMakeScale(1.2, 1.2); } completion:^(BOOL finished) { [UIView animateWithDuration:0.2 animations:^{ tabBarButton.transform = CGAffineTransformIdentity; }]; }]; } } ``` #### 方案2: 上移 + 高亮 ```objc - (void)animateSelectionForButton:(UIView *)button { // 所有按钮复位 for (UIView *view in self.subviews) { if ([view isKindOfClass:NSClassFromString(@"UITabBarButton")]) { [UIView animateWithDuration:0.2 animations:^{ view.transform = CGAffineTransformIdentity; view.alpha = 0.6; }]; } } // 选中按钮上移 + 高亮 [UIView animateWithDuration:0.3 delay:0 usingSpringWithDamping:0.7 initialSpringVelocity:0.3 options:UIViewAnimationOptionCurveEaseOut animations:^{ button.transform = CGAffineTransformMakeTranslation(0, -8); button.alpha = 1.0; } completion:nil]; } ``` --- ### 3. 中间按钮改造 如果有中间凸起的发布按钮: #### 方案1: 移除凸起,改为平齐 ```objc // 移除原有的自定义中间按钮逻辑 // 使用普通的 TabBarItem ``` #### 方案2: 改变凸起样式 ```objc // 原: 圆形凸起 // 新: 六边形凸起 - (void)setupCenterButton { // 创建六边形路径 UIBezierPath *hexagonPath = [UIBezierPath bezierPath]; CGFloat radius = 30; CGFloat centerX = self.bounds.size.width / 2; CGFloat centerY = 0; for (int i = 0; i < 6; i++) { CGFloat angle = M_PI / 3 * i; CGFloat x = centerX + radius * cos(angle); CGFloat y = centerY + radius * sin(angle); if (i == 0) { [hexagonPath moveToPoint:CGPointMake(x, y)]; } else { [hexagonPath addLineToPoint:CGPointMake(x, y)]; } } [hexagonPath closePath]; // 创建形状层 CAShapeLayer *hexagonLayer = [CAShapeLayer layer]; hexagonLayer.path = hexagonPath.CGPath; hexagonLayer.fillColor = [AppThemeColor primaryColor].CGColor; self.centerButton.layer.mask = hexagonLayer; } ``` --- ## 🔧 具体实施步骤 ### 步骤1: 备份原 TabBar 文件 ```bash cd "/Users/edwinqqq/Local/Company Projects/peko-ios/YuMi/Modules/YMTabbar" cp View/TabbarViewController.m View/TabbarViewController.m.backup cp View/XPTabBar.m View/XPTabBar.m.backup ``` ### 步骤2: 修改 TabBar 初始化逻辑 ```objc // TabbarViewController.m - (void)viewDidLoad { [super viewDidLoad]; // 1. 创建新的 ViewController 顺序 [self setupViewControllers]; // 2. 设置新的 TabBar 样式 [self setupTabBarAppearance]; // 3. 配置 TabBarItem [self setupTabBarItems]; // 4. 设置选中动画 [self setupSelectionAnimation]; } - (void)setupViewControllers { // 根据选择的方案A/B/C调整 // 方案A: 改变顺序 NSArray *viewControllers = @[ [self createMomentsVC], [self createHomeVC], [self createBlankVC], [self createMineVC], [self createMessageVC] ]; self.viewControllers = viewControllers; } - (void)setupTabBarAppearance { // 应用新的视觉样式 self.tabBar.tintColor = [AppThemeColor tabBarSelectedColor]; self.tabBar.unselectedItemTintColor = [AppThemeColor tabBarNormalColor]; self.tabBar.backgroundColor = [AppThemeColor tabBarBackgroundColor]; // 添加阴影或其他装饰 [self setupFloatingTabBar]; // 或 setupTabBarShadow } - (void)setupTabBarItems { // 更新所有 Tab 的图标和文字 NSArray *titles = @[@"动态", @"首页", @"", @"我的", @"消息"]; NSArray *normalIcons = @[@"tab_moments_normal", @"tab_home_normal", @"", @"tab_mine_normal", @"tab_message_normal"]; NSArray *selectedIcons = @[@"tab_moments_selected", @"tab_home_selected", @"", @"tab_mine_selected", @"tab_message_selected"]; for (int i = 0; i < self.viewControllers.count; i++) { UIViewController *vc = self.viewControllers[i]; vc.tabBarItem.title = titles[i]; vc.tabBarItem.image = [[UIImage imageNamed:normalIcons[i]] imageWithRenderingMode:UIImageRenderingModeAlwaysOriginal]; vc.tabBarItem.selectedImage = [[UIImage imageNamed:selectedIcons[i]] imageWithRenderingMode:UIImageRenderingModeAlwaysOriginal]; // 设置标题样式 [vc.tabBarItem setTitleTextAttributes:@{ NSForegroundColorAttributeName: [AppThemeColor tabBarNormalColor], NSFontAttributeName: [UIFont systemFontOfSize:10] } forState:UIControlStateNormal]; [vc.tabBarItem setTitleTextAttributes:@{ NSForegroundColorAttributeName: [AppThemeColor tabBarSelectedColor], NSFontAttributeName: [UIFont boldSystemFontOfSize:10] } forState:UIControlStateSelected]; } } ``` ### 步骤3: 处理业务逻辑中的 Tab 跳转 很多地方可能硬编码了 Tab 的 index,需要全局搜索并更新: ```bash # 搜索所有 TabBar 跳转代码 grep -rn "selectedIndex" YuMi/Modules --include="*.m" # 常见的模式 grep -rn "tabBarController.selectedIndex = " YuMi/Modules --include="*.m" ``` **建议**:创建一个枚举来管理 Tab index,而不是硬编码数字 ```objc // TabbarViewController.h typedef NS_ENUM(NSInteger, AppTabIndex) { AppTabIndexMoments = 0, AppTabIndexHome = 1, AppTabIndexPublish = 2, AppTabIndexMine = 3, AppTabIndexMessage = 4 }; // 使用 self.tabBarController.selectedIndex = AppTabIndexHome; ``` ### 步骤4: 更新推送和深度链接 如果有推送通知或深度链接跳转到特定 Tab,也需要更新: ```objc // AppDelegate.m 或 深度链接处理 - (void)handleNotification:(NSDictionary *)userInfo { NSString *targetTab = userInfo[@"target_tab"]; TabbarViewController *tabVC = (TabbarViewController *)self.window.rootViewController; if ([targetTab isEqualToString:@"message"]) { tabVC.selectedIndex = AppTabIndexMessage; // 更新为新的 index } // ... 其他 Tab } ``` --- ## 🎨 图标设计建议 ### 1. 扁平风格 → 3D 风格 或者反过来,如果原来是 3D,改为扁平。 ### 2. 线条图标 → 填充图标 ``` 原: ☐ ☐ ☐ ☐ (线框) 新: ■ ■ ■ ■ (填充) ``` ### 3. 图标位置变化 ```objc // 图标上移,文字下移 - (void)setupTabBarItemLayout { for (UIViewController *vc in self.viewControllers) { vc.tabBarItem.imageInsets = UIEdgeInsetsMake(-2, 0, 2, 0); vc.tabBarItem.titlePositionAdjustment = UIOffsetMake(0, 2); } } ``` --- ## 📱 响应式适配 确保 TabBar 在不同设备上都正常显示: ```objc - (void)setupTabBarForDevice { CGFloat screenWidth = [UIScreen mainScreen].bounds.size.width; CGFloat screenHeight = [UIScreen mainScreen].bounds.size.height; // iPad 适配 if (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPad) { self.tabBar.itemWidth = 100; self.tabBar.itemSpacing = 20; } // iPhone SE 等小屏适配 if (screenWidth <= 375) { // 减小图标和文字 for (UIViewController *vc in self.viewControllers) { [vc.tabBarItem setTitleTextAttributes:@{ NSFontAttributeName: [UIFont systemFontOfSize:9] } forState:UIControlStateNormal]; } } // 刘海屏适配 if (@available(iOS 11.0, *)) { CGFloat bottomSafeArea = self.view.safeAreaInsets.bottom; if (bottomSafeArea > 0) { // 有刘海 self.tabBar.frame = CGRectMake(0, screenHeight - 83 - bottomSafeArea, screenWidth, 83 + bottomSafeArea); } } } ``` --- ## ✅ 测试清单 完成 TabBar 改造后,测试以下内容: - [ ] 所有 Tab 都能正常切换 - [ ] Tab 图标和文字显示正确 - [ ] 选中状态颜色正确 - [ ] 选中动画流畅 - [ ] 推送通知跳转正确 - [ ] 深度链接跳转正确 - [ ] 小红点显示正确(未读消息等) - [ ] 旋转屏幕后 TabBar 正常 - [ ] iPad 上显示正常 - [ ] 深色模式下(如果支持)显示正常 --- ## 🎯 差异化效果评估 ### 原 TabBar - 5个固定 Tab - 中间凸起发布按钮 - 紫色主题 - 扁平风格图标 - 无动画 ### 新 TabBar(方案A) - 5个 Tab,顺序改变 - 中间按钮改为六边形 - 橙色主题 - 填充风格图标 - 弹性选中动画 - 浮动卡片样式 **差异度**: 约 80% --- ## 🚀 高级技巧 ### 1. 添加震动反馈 ```objc #import - (void)tabBar:(UITabBar *)tabBar didSelectItem:(UITabBarItem *)item { // 触觉反馈 if (@available(iOS 10.0, *)) { UIImpactFeedbackGenerator *generator = [[UIImpactFeedbackGenerator alloc] initWithStyle:UIImpactFeedbackStyleLight]; [generator impactOccurred]; } else { AudioServicesPlaySystemSound(1519); // Peek feedback } } ``` ### 2. 添加粒子效果 ```objc - (void)addParticleEffectToButton:(UIView *)button { CAEmitterLayer *emitterLayer = [CAEmitterLayer layer]; emitterLayer.emitterPosition = CGPointMake(button.bounds.size.width/2, button.bounds.size.height/2); CAEmitterCell *cell = [CAEmitterCell emitterCell]; cell.birthRate = 10; cell.lifetime = 1.0; cell.velocity = 50; cell.scale = 0.05; cell.contents = (id)[[UIImage imageNamed:@"particle"] CGImage]; emitterLayer.emitterCells = @[cell]; [button.layer addSublayer:emitterLayer]; } ``` ### 3. Lottie 动画图标 ```objc #import - (void)setupLottieTabBarItems { for (int i = 0; i < self.viewControllers.count; i++) { LOTAnimationView *animationView = [LOTAnimationView animationNamed:@"tab_icon_animation"]; animationView.frame = CGRectMake(0, 0, 30, 30); // 添加到 TabBarItem UIViewController *vc = self.viewControllers[i]; // ... 自定义逻辑 } } ``` --- ## 📝 总结 通过以上改造,你的 TabBar 将: 1. ✅ 结构完全不同(顺序/数量) 2. ✅ 视觉完全不同(颜色/样式/图标) 3. ✅ 交互完全不同(动画/反馈) 4. ✅ 代码明显不同(类名/逻辑) **预计改造时间**: 2-3天 **差异化程度**: 80%+ 这将是 App Store 审查中最直观的差异点之一!🎉