Files
real-e-party-iOS/issues/scripts/4_tabbar_refactor_guide.md
edwinQQQ a35a711be6 chore: Initial clean commit
- Removed YuMi/Library/ (138 MB, not tracked)
- Removed YuMi/Resources/ (23 MB, not tracked)
- Removed old version assets (566 files, not tracked)
- Excluded Pods/, xcuserdata/ and other build artifacts
- Clean repository optimized for company server deployment
2025-10-09 16:19:14 +08:00

580 lines
16 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# 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 <AudioToolbox/AudioToolbox.h>
- (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 <Lottie/Lottie.h>
- (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 审查中最直观的差异点之一!🎉