
- 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
16 KiB
16 KiB
TabBar 结构改动指南
📋 当前 TabBar 结构分析
基于 TabbarViewController.h/m
的分析,当前项目的 TabBar 包含以下模块:
现有结构(推测)
- 首页 (Home) -
YMNewHome
- 消息 (Message) -
YMMessage
- 动态 (Moments) -
YMMonents
- 我的 (Mine) -
YMMine
可能还有一个中间的"发布"按钮(常见于直播/社交应用)。
🎯 改造目标
通过调整 TabBar 的结构、顺序、样式,让 App 在使用体验和视觉上都和原项目有明显区别。
🔄 改造方案
方案A: 改变顺序
原顺序:首页 → 消息 → [发布] → 动态 → 我的
新顺序:动态 → 首页 → [发布] → 我的 → 消息
代码修改:
// 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,将其整合到首页或消息中。
新结构:首页 → 消息 → 我的 → 设置
- (void)viewDidLoad {
[super viewDidLoad];
NSArray *viewControllers = @[
[self createHomeVC], // 首页
[self createMessageVC], // 消息
[self createMineVC], // 我的
[self createSettingsVC] // 新增:设置
];
self.viewControllers = viewControllers;
// 移除中间的凸起按钮
// self.customTabBar = nil;
}
方案C: 完全重新设计(4个→6个)
增加更多功能入口,显得是不同的产品定位。
新结构:发现 → 直播 → 短视频 → 消息 → 商城 → 我的
- (void)viewDidLoad {
[super viewDidLoad];
NSArray *viewControllers = @[
[self createDiscoverVC], // 发现(重组的首页)
[self createLiveVC], // 直播(原首页的一部分)
[self createVideoVC], // 短视频(新增或从动态拆分)
[self createMessageVC], // 消息
[self createShopVC], // 商城(新增或从我的拆分)
[self createMineVC] // 我的
];
self.viewControllers = viewControllers;
}
🎨 视觉改造
1. TabBar 样式改变
方案1: 平面风格 → 卡片风格
// 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: 固定底部 → 浮动底部
- (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: 缩放动画
// 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: 上移 + 高亮
- (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: 移除凸起,改为平齐
// 移除原有的自定义中间按钮逻辑
// 使用普通的 TabBarItem
方案2: 改变凸起样式
// 原: 圆形凸起
// 新: 六边形凸起
- (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 文件
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 初始化逻辑
// 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,需要全局搜索并更新:
# 搜索所有 TabBar 跳转代码
grep -rn "selectedIndex" YuMi/Modules --include="*.m"
# 常见的模式
grep -rn "tabBarController.selectedIndex = " YuMi/Modules --include="*.m"
建议:创建一个枚举来管理 Tab index,而不是硬编码数字
// TabbarViewController.h
typedef NS_ENUM(NSInteger, AppTabIndex) {
AppTabIndexMoments = 0,
AppTabIndexHome = 1,
AppTabIndexPublish = 2,
AppTabIndexMine = 3,
AppTabIndexMessage = 4
};
// 使用
self.tabBarController.selectedIndex = AppTabIndexHome;
步骤4: 更新推送和深度链接
如果有推送通知或深度链接跳转到特定 Tab,也需要更新:
// 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. 图标位置变化
// 图标上移,文字下移
- (void)setupTabBarItemLayout {
for (UIViewController *vc in self.viewControllers) {
vc.tabBarItem.imageInsets = UIEdgeInsetsMake(-2, 0, 2, 0);
vc.tabBarItem.titlePositionAdjustment = UIOffsetMake(0, 2);
}
}
📱 响应式适配
确保 TabBar 在不同设备上都正常显示:
- (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. 添加震动反馈
#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. 添加粒子效果
- (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 动画图标
#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 将:
- ✅ 结构完全不同(顺序/数量)
- ✅ 视觉完全不同(颜色/样式/图标)
- ✅ 交互完全不同(动画/反馈)
- ✅ 代码明显不同(类名/逻辑)
预计改造时间: 2-3天
差异化程度: 80%+
这将是 App Store 审查中最直观的差异点之一!🎉