内容简介:最近项目改版里,产品设计重新设计了tabbar动画,旨在提升app的逼格。。。 设计图是借鉴淘宝的tabBar:找资料查找下,还没有相关开源的代码,好吧,那就自己开干吧。删除系统tabBar,创建自定义tabBar,
最近项目改版里,产品设计重新设计了tabbar动画,旨在提升app的逼格。。。 设计图是借鉴淘宝的tabBar:
找资料查找下,还没有相关开源的代码,好吧,那就自己开干吧。
先拆解功能点:
手势上滑 - logo向下切换到小火箭; 手势下滑 - 小火箭向上切换到logo;
开始各个击破吧
1. 自定义tabBar,高度56
删除系统tabBar,创建自定义tabBar,
@implementation WMTabBar // 删除系统tabbar的UITabBarButton - (void)layoutSubviews { [super layoutSubviews]; for (UIView *view in self.subviews) { if ([view isKindOfClass:NSClassFromString(@"UITabBarButton")]) { [view removeFromSuperview]; } } } // 根据配置信息创建自定义tabBar + (instancetype)tabBarWithTitleArray:(NSArray *)titleArray imageArray:(NSArray *)imageArray selectedImageArray:(NSArray *)selectedImageArray { WMTabBar *tabBar = [[WMTabBar alloc] init]; tabBar.titleArray = titleArray; tabBar.imageArray = imageArray; tabBar.selectedImageArray = selectedImageArray; [tabBar setupUI]; return tabBar; } - (void)setupUI { self.lastSelectIndex = 100;//默认为100 self.backgroundColor = [UIColor whiteColor]; for (int i = 0; i < self.titleArray.count; i++) { CGFloat itemWidth = (kScreen_width/self.titleArray.count); CGRect frame = CGRectMake(i*itemWidth, 0, itemWidth, 56); WMTabBarItem *tabBarItem = [[WMTabBarItem alloc] initWithFrame:frame index:i]; tabBarItem.tag = i ; UITapGestureRecognizer *tap = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(tabBarItemClickAction:)]; [tabBarItem addGestureRecognizer:tap]; [self addSubview:tabBarItem]; [self.itemArray addObject:tabBarItem]; } // 记录选中index, 在其setter方法里重写逻辑 self.selectedIndex = 0; } <!-- 选中index 重写setter方法,在里面做tabBar的item的内容动态配置 --> - (void)setSelectedIndex:(NSInteger )selectedIndex { _selectedIndex = selectedIndex; [self.itemArray enumerateObjectsUsingBlock:^(WMTabBarItem *tabBarItem, NSUInteger idx, BOOL * _Nonnull stop) { // 当遍历的idx=selectedIndex时,记录选中状态 BOOL selected = (idx == selectedIndex); // 配置tabBarItem的内容信息 [tabBarItem configTitle:self.titleArray[idx] normalImage:self.imageArray[idx] selectedImage:self.selectedImageArray[idx] index:idx selected:selected lastSelectIndex:self.lastSelectIndex]; // 当遍历到最后一个时,赋值lastSelectIndex if (idx == (self.itemArray.count-1)) { self.lastSelectIndex = selectedIndex; } }]; } 复制代码
在WMTabBar里仿照系统tabBar的点击方法,添加两个wmTabBar代理方法,以满足项目里tabBar点击选中或点击tabBar时根据登录状态进行是否选中等操作:
@protocol WMTabBarDelegate <NSObject> /** 选中tabbar */ - (void)wmtabBar:(WMTabBar *)wmTabBar selectedWMTabBarItemAtIndex:(NSInteger)index; /** 是否可选tabbar */ - (BOOL)wmtabBar:(WMTabBar *)wmTabBar shouldSelectedWMTabBarItemAtIndex:(NSInteger)index; @end 复制代码
在WMTabBarController里设置tabBar
// 重写tabbar的frame,改变tabbar高度 - (void)viewDidLayoutSubviews { [super viewDidLayoutSubviews]; CGRect frame = self.tabBar.frame; if (frame.size.height != kTABBARHEIGHT) { frame.size.height = kTABBARHEIGHT; frame.origin.y = self.view.frame.size.height - frame.size.height; self.tabBar.frame = frame; } } //添加子模块 - (void)creatTabBarWithChildVCArray:(NSArray *)childVCArray titleArray:(NSArray *)titleArray imageArray:(NSArray *)imageArray selectedImageArray:(NSArray *)selectedImageArray { for (UIViewController *viewController in childVCArray) { MPNavigationController *navigationController = [[MPNavigationController alloc] initWithRootViewController:viewController]; [self.controllersArray addObject:navigationController]; } self.wmTabBar = [WMTabBar tabBarWithTitleArray:titleArray imageArray:imageArray selectedImageArray:selectedImageArray]; self.wmTabBar.tabBarDelegate = self; [self setValue:self.wmTabBar forKeyPath:@"tabBar"]; self.viewControllers = self.controllersArray; } 复制代码
2. tab显示:首页tab在选中时是大logo 无文字,未选中时是图片文字 ;其他tab未选中和选中都是图片文字
在tabBarItem里创建显示UI
@implementation WMTabBarItem - (instancetype)initWithFrame:(CGRect)frame index:(NSInteger )index { self = [super initWithFrame:frame]; if (self) { [self addSubview:self.titleLabel]; [self addSubview:self.imageView]; [self addSubview:self.homeTabSelectedBgView]; self.imageView.frame = CGRectMake(self.bounds.size.width/2-14, 7, 28, 28); self.titleLabel.frame = CGRectMake(0, CGRectGetMaxY(self.imageView.frame)+2, self.bounds.size.width, 14); self.homeTabSelectedBgView.frame = CGRectMake(self.bounds.size.width/2-21, 7, 42, 42); if (index == 0) { // 当为首页tab时,加上以下内容 [self addSubview:self.homeTabSelectedBgView]; // /** 第一种方案 */ // [self.homeTabSelectedBgView addSubview:self.homeTabAnimateImageView]; // self.homeTabAnimateImageView.frame = CGRectMake(0, 0, 32, 32); // self.homeTabAnimateImageView.center = CGPointMake(self.homeTabSelectedBgView.frame.size.width/2, self.homeTabSelectedBgView.frame.size.height/2); /** 第二种方案 */ [self.homeTabSelectedBgView addSubview:self.collectionView]; self.homeTabSelectedBgView.frame = CGRectMake(self.bounds.size.width/2-21, 7, 42, 42); self.collectionView.frame = CGRectMake(0, 0, 42, 42); self.collectionView.center = CGPointMake(self.homeTabSelectedBgView.frame.size.width/2, self.homeTabSelectedBgView.frame.size.height/2); [self.collectionView registerClass:[WMTabBarItemCell class] forCellWithReuseIdentifier:NSStringFromClass([WMTabBarItemCell class])]; } } return self; } 复制代码
在tab点击事件里处理:
// 当点击tab的item时,执行 - (void)configTitle:(NSString *)title normalImage:(NSString *)normalImage selectedImage:(NSString *)selectedImage index:(NSInteger)index selected:(BOOL)selected lastSelectIndex:(NSInteger )lastSelectIndex { self.titleLabel.text = title; // 当index == 0, 即首页tab if (index == 0) { if (selected) { [self.homeTabSelectedBgView setImage:[UIImage imageNamed:@"tabbar_home_selecetedBg"]]; self.homeTabSelectedBgView.hidden = NO; YES;self.imageView.hidden = self.titleLabel.hidden = YES; // /** 第一种方案 */ // [self.homeTabAnimateImageView setImage:[UIImage imageNamed:@"tabbar_home_selecetedLogo"]]; // /** 第二种方案 默认显示第一个cell 所以不用在这里设置图片 */ // 如果本次点击和上次是同一个tab 都是第0个,则执行push动画,否则执行放大缩小动画 if (lastSelectIndex == index) { if (self.flag) { // 如果已经是火箭状态,则点击切换logo,且发通知 让首页滑到顶部 [self pushHomeTabAnimationDown]; [[NSNotificationCenter defaultCenter] postNotificationName:@"kPushDownAnimationScrollTopNotification" object:nil]; } }else { [self animationWithHomeTab]; } }else { [self.imageView setImage:[UIImage imageNamed:normalImage]]; self.homeTabSelectedBgView.hidden = YES; self.imageView.hidden = self.titleLabel.hidden = NO; } }else { // 其他tab self.homeTabSelectedBgView.hidden = YES; self.imageView.hidden = self.titleLabel.hidden = NO; if (selected) { [self.imageView setImage:[UIImage imageNamed:selectedImage]]; self.titleLabel.textColor = [self colorFromHexRGB:@"18A2FF"]; // 如果本次点击和上次是同一个tab 则无反应,否则执行放大缩小动画 if (lastSelectIndex != index) { [self animationWithNormalTab]; } }else { [self.imageView setImage:[UIImage imageNamed:normalImage]]; self.titleLabel.textColor = [self colorFromHexRGB:@"575D66"]; } } } 复制代码
就是在tab点击事件里做处理:
- 当index==0 即首页tab时,根据是否是seleted状态 来判断显示是大logo控件还是正常文字图片控件。
- 其他tab时,隐藏大logo控件,只显示图片文字控件,再根据是否是seleted状态 来判断选中和未选中时的图片及文字颜色配置。
3.tab切换:tab之间相互点击切换选中时的缩小放大的动画
tab在相互点击切换选中时的缩小放大动画,通过CABasicAnimation来实现:
/** * tab之间切换动画 */ // 首页tab缩小放大动画 - (void)animationForHomeTab { CABasicAnimation *animation = [CABasicAnimation animationWithKeyPath:@"transform.scale"]; animation.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseInEaseOut]; animation.duration = 0.2f; animation.fromValue = [NSNumber numberWithFloat:0.5f]; animation.toValue = [NSNumber numberWithFloat:1.f]; [self.homeTabSelectedBgView.layer addAnimation:animation forKey:nil]; } // 其他tab缩小放大动画 - (void)animationForNormalTab { CABasicAnimation *animation = [CABasicAnimation animationWithKeyPath:@"transform.scale"]; animation.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseInEaseOut]; animation.duration = 0.25f; animation.fromValue = [NSNumber numberWithFloat:0.5f]; animation.toValue = [NSNumber numberWithFloat:1.f]; [self.imageView.layer addAnimation:animation forKey:nil]; [self.titleLabel.layer addAnimation:animation forKey:nil]; } 复制代码
效果如下:
4.当首页滑动到一定距离时,首页tab的大logo和小火箭执行切换动画
观察设计图,可以得出根据首页的滑动偏移量及滑动手势,来确定滑动动画方案:
在一次滑动行为中:当偏移量>阈值,且手势上滑 - logo向下切换到小火箭;当偏移量<阈值,且手势下滑 - 小火箭向上切换到logo;
首页里滑动代理实现:
// tabBar动画 - 判断滑动手势,再根据手势,偏移量 判断动画类型 - (void)tabBarAnimateWithScrollView:(UIScrollView *)scrollView { CGFloat currentPostionOffsetY = scrollView.contentOffset.y; if (currentPostionOffsetY > self.lastPositionOffestY) { NSLog(@"手势上滑"); // tabBar动画 if (self.tabAnimateOnceScrollFlag) { // 在一次滑动中,且currentPostionOffsetY>456,执行logo切换火箭:rocket:动画 if ((currentPostionOffsetY > 456.f)) { NSLog(@"执行-切换火箭"); [[AppLoginHandle sharedInstance].tabBarController pushHomeTabBarAnimationType:anmationDirectionUp]; self.tabAnimateOnceScrollFlag = NO; } } }else { NSLog(@"手势下滑"); // tabBar动画 if (self.tabAnimateOnceScrollFlag) { // 在一次滑动中,下滑手势, 且currentPostionOffsetY<456,执行火箭:rocket:切换logo动画 if ((currentPostionOffsetY < 456.f)) { NSLog(@"触发-切换logo"); [[AppLoginHandle sharedInstance].tabBarController pushHomeTabBarAnimationType:anmationDirectionDown]; self.tabAnimateOnceScrollFlag = NO; } } } } // 当开始滚动视图时,执行该方法。一次有效滑动(开始滑动,滑动一小段距离,只要手指不松开,只算一次滑动),只执行一次。 - (void)scrollViewWillBeginDragging:(UIScrollView *)scrollView { if ([scrollView isEqual:self.collectionView]) { self.tabAnimateOnceScrollFlag = YES; self.lastPositionOffestY = scrollView.contentOffset.y; } } 复制代码
WMTabBar里暴露出外部调用切换动画的方法如下:
// logo和火箭切换动画的枚举anmationDirection typedef NS_ENUM(NSUInteger, anmationDirection) { anmationDirectionUp,//push动画,火箭头出来,logo下去 anmationDirectionDown,//push动画,火箭头下去,logo出来 }; @class WMTabBar; @protocol WMTabBarDelegate <NSObject> /** 选中tabbar */ - (void)wmtabBar:(WMTabBar *)wmTabBar didSelectWMTabBarItemAtIndex:(NSInteger)index; /** 是否可选tabbar */ - (BOOL)wmtabBar:(WMTabBar *)wmTabBar shouldSelectWMTabBarItemAtIndex:(NSInteger)index; @end @interface WMTabBar : UITabBar @property (nonatomic, weak) id <WMTabBarDelegate> tabBarDelegate; @property (nonatomic, assign) anmationDirection anmationDirection; /** 实例化 */ + (instancetype)tabBarWithTitleArray:(NSArray *)titleArray imageArray:(NSArray *)imageArray selectedImageArray:(NSArray *)selectedImageArray; // 外部指定跳转到某个tab时调用 - (void)selectedTabbarAtIndex:(NSNumber *)index; // 暴露外部的切换动画logo和火箭的方法 - (void)pushHomeTabBarAnimationType:(anmationDirection )anmationDirection; @end 复制代码
WMTabBarItem里实现首页tab的小火箭和logo之间切换动画
这里写了两种方法,第一种是最开始尝试的,通过CATransition的push动画,来达到一个imageView控件的两个图片切换,如下:
- 第一种方案 push动画方案:
// push动画,火箭头出来 -(void)pushHomeTabAnimationUp { self.flag = YES; // /** 第一种方案 */ // [self.homeTabAnimateImageView setImage:[UIImage imageNamed:@"tabbar_home_selecetedPush"]]; // CATransition *animation = [CATransition animation]; // animation.type = kCATransitionPush;//设置动画的类型 // animation.subtype = kCATransitionFromTop; //设置动画的方向 // animation.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseInEaseOut]; // animation.duration = 0.25f; // [self.homeTabAnimateImageView.layer addAnimation:animation forKey:@"pushAnimation"]; } // push动画,火箭头落下 -(void)pushHomeTabAnimationDown { self.flag = NO; // /** 第一种方案 */ // [self.homeTabAnimateImageView setImage:[UIImage imageNamed:@"tabbar_home_selecetedLogo"]]; // CATransition *animation = [CATransition animation]; // animation.type = kCATransitionPush;//设置动画的类型 // animation.subtype = kCATransitionFromBottom; //设置动画的方向 // animation.duration = 0.25f; // [self.homeTabAnimateImageView.layer addAnimation:animation forKey:@"pushAnimation"]; } 复制代码
效果如下:
虽然能实现功能,但在切换过程中,会有残留效果,这显示是不太美好的,再想想有没有更好的实现方法。
然后就想到了collectionView了。
- 第二种方案 collection滑动item方案:
把collectionView设置成首页tab大小,通过让collection的cell的scrollToItem方法, 即滑动到第n个item来达到切换动画效果,如下:
// push动画,火箭头出来 -(void)pushHomeTabAnimationUp { self.flag = YES; /** 第二种方案 */ [self.collectionView scrollToItemAtIndexPath:[NSIndexPath indexPathForItem:1 inSection:0] atScrollPosition:UICollectionViewScrollPositionCenteredVertically animated:YES]; } // push动画,火箭头落下 -(void)pushHomeTabAnimationDown { self.flag = NO; /** 第二种方案 */ [self.collectionView scrollToItemAtIndexPath:[NSIndexPath indexPathForItem:0 inSection:0] atScrollPosition:UICollectionViewScrollPositionCenteredVertically animated:YES]; } 复制代码
漂亮!
到此,新版tabBar实现就完成了!
以上就是本文的全部内容,希望本文的内容对大家的学习或者工作能带来一定的帮助,也希望大家多多支持 码农网
猜你喜欢:- 如何利用强化学习设计出更好的火箭发动机
- 火箭五年四遇勇士,终究还是败了
- 火箭军总医院卢敬泰:互联网+医疗大数据辅助诊疗研究
- 滑动验证码的原理并利用 Vue 实现滑动验证码
- Flink 滑动窗口优化
- Flink 滑动窗口优化
本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。
How to Build a Billion Dollar App
George Berkowski / Little, Brown Book Group / 2015-4-1 / USD 24.95
Apps have changed the way we communicate, shop, play, interact and travel and their phenomenal popularity has presented possibly the biggest business opportunity in history. In How to Build a Billi......一起来看看 《How to Build a Billion Dollar App》 这本书的介绍吧!