iOS 开源一个高度可定制支持各种动画效果,支持单击双击,小红点,支持自定义不规则按钮的tabbar...

本文主要是介绍iOS 开源一个高度可定制支持各种动画效果,支持单击双击,小红点,支持自定义不规则按钮的tabbar...,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

TYTabbarAnimationDemo

业务需求导致需要做一个tabbar,里面的按钮点击带有动画效果,tabbar中间的按钮凸出,凸出部分可以点击,支持badge 小红点等,为此封装了一个高度可定制的tabbar -> TYTabBar demo下载地址:https://github.com/qqcc1388/TYTabbarAnimationDemo

TYTabBar可以快速实现以下功能

  1. 每个Item都有单击,双击事件回调
  2. tem可以支持多种动画(帧动画,缩放动画,旋转动画),每个Item都可以单独设置
  3. 支持badgeText,支持小红点功能
  4. 只需要配置一下,就可以实现不规则按钮效果,并且超出边界仍然有点击效果
  5. 支持横竖屏切换

效果图(由于图片资源的问题导致动画切换比较生硬,更改为满足尺寸的资源就好啦)

950551-20170824101439605-363648746.gif
950551-20170824101453089-1952653490.gif

思路回顾(TYTabBar)

系统的Tabbar功能不算完善,有时候没法完全满足需求,我们这里通过kvc的方式把系统的tabbar替换成我们自己定义的tabbar。
    [self setValue:tabbar forKeyPath:@"tabBar"];
自定义一个TYTabBar继承UITabBar这样就可以继承很多系统TabBar既有很多属性和功能
@interface TYTabBar : UITabBar
初始化配置信息(很重要关系到Item个数,PlusItem的位置)
#define barItemCount                5                               //tabbarItem 个数
#define barItemPlusButtonIndex      2                              //➕按钮的位置  -1表示不存在+按钮  从0开始
#define barItemFontSize             12                              //字体大小
#define barItemNomalTextColor       [UIColor grayColor]             //字体默认颜色
#define barItemSelectedTextColor    [UIColor redColor]              //选中字体颜色
#define barItemSubMargin            3                               //文字和图片的间距
初始化需要TYTabBar中需要展示的按钮并保存起来,并添加点击事件 传入默认第几个tabbarItem默认被选中
-(void)loadItemsWithData:(NSArray<TYBarItemModel *> *)itemModels defaultSelect:(NSInteger)index{//初始化NSMutableArray *mutalArr = [NSMutableArray array];TYAnimationButton *tempItem = nil;for (int i = 0; i < barItemCount; i++) {//取出modelTYBarItemModel *model = [itemModels objectAtIndex:i];TYAnimationButton *button = [[TYAnimationButton alloc] init];button.images = model.images;[button setImage:[UIImage imageNamed:model.normalImage] forState:UIControlStateNormal];[button setImage:[UIImage imageNamed:model.selectedImage] forState:UIControlStateSelected];[button setTitle:model.title forState:UIControlStateNormal];button.tag = i;button.titleLabel.font = [UIFont systemFontOfSize:barItemFontSize];[button setTitleColor:barItemSelectedTextColor forState:UIControlStateSelected];[button setTitleColor:barItemNomalTextColor forState:UIControlStateNormal];[button addTarget:self action:@selector(itemClick:) forControlEvents:UIControlEventTouchDown];button.layoutType = LXButtonLayoutTypeImageTop;button.subMargin = barItemSubMargin;button.animationType = model.animationType;[self addSubview:button];//第index按钮默认选中if (i == index) {tempItem = button;}//保存按钮[mutalArr addObject:button];}self.myItems = mutalArr;//设置默认选中第index个if (tempItem) {[self itemClick:tempItem];}else{//如果传入的index无效 则默认选中第0个TYAnimationButton *item = self.myItems.firstObject;[self itemClick:item];}
}
在TabBar的layoutSubviews方法中找到对应的系统的TabBarItem并隐藏起来,创建我们自己的Button并占用系统TabBarItem的位置
-(void)layoutSubviews{[super layoutSubviews];Class class = NSClassFromString(@"UITabBarButton");int btnIndex = 0;//假设这里有5个itemCGFloat width = self.bounds.size.width/barItemCount*1.0;CGFloat height = self.bounds.size.height;for (UIView *btn in self.subviews) {//遍历tabbar的子控件if ([btn isKindOfClass:class]) {//先隐藏系统的tabbarItembtn.hidden = YES;//取出前面保存的按钮UIButton *item = [self.myItems objectAtIndex:btnIndex];//设置item的位置item.frame = CGRectMake(width*btnIndex, 0, width, height);if (barItemPlusButtonIndex == btnIndex) {  //plusButton位置  具体偏移根据时间情况进行调节item.frame = CGRectMake(width*btnIndex, -20, width, height+20);item.subMargin = 10;}btnIndex++;}}
}
单击 双击事件处理和传递(这里通过代理将信息传递出去realDelegate一定要要实现,涉及到控制器跳转)
-(void)itemClick:(TYAnimationButton *)item{//双击效果处理//2次双击之间间隔至少1sstatic  NSTimeInterval lastClickTime = 0;if ([self checkIsDoubleClick:item]) {NSTimeInterval clickTime = [NSDate timeIntervalSinceReferenceDate];if (clickTime - lastClickTime > 1) {  //去掉连击的可能性if (_realDelegate && [_realDelegate respondsToSelector:@selector(tabBar:doubleClick:)]) {[self.realDelegate tabBar:self doubleClick:item.tag];}}lastClickTime = clickTime;}//按钮重复点击没有效果if (item == _lastItem && self.canRepeatClick) { //可以重复点击if (!item.isAnimating) { //正在动画什么都不做否则开始动画[item animationStart];}}else if(item != _lastItem){  //不可以重复点击//先把上次item动画关闭_lastItem.selected = NO;[_lastItem animationStop];//新点击的item动画开启item.selected = YES;[item animationStart];//把按钮的点击状态传到出去 让tabbarController可以切换控制器if (_realDelegate && [_realDelegate respondsToSelector:@selector(tabBar:clickIndex:)]) {[self.realDelegate tabBar:self clickIndex:item.tag];}_lastItem = item;}}- (BOOL)checkIsDoubleClick:(UIButton *)currentBtn
{static UIButton *lastBtn = nil;static NSTimeInterval lastClickTime = 0;if (lastBtn != currentBtn) {lastBtn = currentBtn;lastClickTime = [NSDate timeIntervalSinceReferenceDate];return NO;}NSTimeInterval clickTime = [NSDate timeIntervalSinceReferenceDate];if (clickTime - lastClickTime > 0.5 ) {lastClickTime = clickTime;return NO;}lastClickTime = clickTime;return YES;
}
badgeText 小红点设置(参考JSBadgeView并在源码上做了一点修改) 显示数字 @"2" 不显示内容@""或者nil 显示小红点@"."
-(void)badgeText:(NSString *)text forIndex:(NSInteger)index{//给指定的badgeText设置角标if (index < 0 || index >(self.myItems.count - 1)) {return;}TYAnimationButton *item = self.myItems[index];//设置角标[item setBadgeText:text];}

思路回顾(TYAnimationButton)

TYAnimationButton是整个TYTabBar的核心,每一个Item都是一个TYAnimationButton
提供的动画类型
typedef NS_ENUM(NSUInteger, TYBarItemAnimationType) {TYBarItemAnimationTypeNomal = 0, //系统默认tabar效果TYBarItemAnimationTypeFrames,    //帧动画(imageView)TYBarItemAnimationTypeScale,     //缩放动画TYBarItemAnimationTypeRotate     //旋转动画
};
关于动画提供了2个动画方法 一个开始动画,一个结束动画,如果是帧动画,需要传入动画帧
#pragma mark - 动画
-(void)animationStart{if (_animationType == TYBarItemAnimationTypeNomal) {  //系统默认不带动画}else if(_animationType == TYBarItemAnimationTypeFrames){  //帧动画if (_images) {  //有提供动画图片的才可以动画if (!self.imageView.isAnimating) {  //没有动画 则开启动画 如果当前正在动画 则什么都不做[self frameAnimation];}}}else if(_animationType == TYBarItemAnimationTypeScale){  //[self scaleAnimationRepeatCount:1];}else if(_animationType == TYBarItemAnimationTypeRotate){[self rotateAnimation];}else{}
}-(void)animationStop{if (_animationType == TYBarItemAnimationTypeNomal) {}else if(_animationType == TYBarItemAnimationTypeFrames){if (_images) {  //有提供动画图片的才可以动画if (self.imageView.isAnimating){  //正在动画 则开始动画self.imageView.animationImages = nil;[self.imageView stopAnimating];}}}else if(_animationType == TYBarItemAnimationTypeScale){}else if(_animationType == TYBarItemAnimationTypeRotate){}else{}
}-(void)frameAnimation{//设置动画图片 给button imageView 添加帧动画UIImageView * imageView = self.imageView;//设置动画帧NSMutableArray *mutalImages = [NSMutableArray array];for (NSString *imageName in self.images) {[mutalImages addObject:[UIImage imageNamed:imageName]];}imageView.animationImages= mutalImages;//设置动画总时间imageView.animationDuration = _duration;//设置重复次数,0表示无限imageView.animationRepeatCount = 1;[imageView startAnimating];
}//缩放动画
- (void)scaleAnimationRepeatCount:(float)repeatCount {//需要实现的帧动画,这里根据需求自定义CAKeyframeAnimation *animation = [CAKeyframeAnimation animation];animation.keyPath = @"transform.scale";animation.values = @[@1.0,@1.3,@0.9,@1.15,@0.95,@1.02,@1.0];animation.duration = 1;animation.repeatCount = repeatCount;animation.calculationMode = kCAAnimationCubic;[self.imageView.layer addAnimation:animation forKey:nil];
}//旋转动画
- (void)rotateAnimation {// 针对旋转动画,需要将旋转轴向屏幕外侧平移,最大图片宽度的一半// 否则背景与按钮图片处于同一层次,当按钮图片旋转时,转轴就在背景图上,动画时会有一部分在背景图之下。// 动画结束后复位
//    CGFloat oldZPosition = self.layer.zPosition;//0self.layer.zPosition = 65.f / 2;[UIView animateWithDuration:0.32 delay:0 options:UIViewAnimationOptionCurveEaseIn animations:^{self.imageView.layer.transform = CATransform3DMakeRotation(M_PI, 0, 1, 0);} completion:nil];dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(0.2 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{[UIView animateWithDuration:0.70 delay:0 usingSpringWithDamping:1 initialSpringVelocity:0.2 options:UIViewAnimationOptionCurveEaseOut animations:^{self.imageView.layer.transform = CATransform3DMakeRotation(2 * M_PI, 0, 1, 0);} completion:nil];});
}
给每个TYAnimationButton添加一个badgeView使其具备角标的功能 监听屏幕横竖屏变化并实时修改badgeView的位置
/**角标x轴方向的偏移 默认15*/
@property (nonatomic,assign) CGFloat badgeOffsetX;/**角标y轴方向的偏移 默认15*/
@property (nonatomic,assign) CGFloat badgeOffsetY;/**角标x轴方向的偏移(横屏状态) 默认15 请根据具体需求微调*/
@property (nonatomic,assign) CGFloat badgeLandscapeOffsetX;/**角标y轴方向的偏移(横屏状态) 默认40 请根据具体需求微调*/
@property (nonatomic,assign) CGFloat badgeLandscapeOffsetY;-(void)layoutSubviews{[super layoutSubviews];if((self.bounds.size.width !=0 && !self.badgeView) || self.orientation){//先移除badgeView[self.badgeView removeFromSuperview];//重新添加新的badgeViewself.badgeView = [[JSBadgeView alloc] initWithParentView:self alignment:JSBadgeViewAlignmentTopRight];//设置角标参数_badgeView.badgeTextFont = [UIFont systemFontOfSize:12];if (self.orientation == UIDeviceOrientationLandscapeLeft || self.orientation == UIDeviceOrientationLandscapeRight) { //横屏状态_badgeView.badgePositionAdjustment = CGPointMake(-_badgeLandscapeOffsetX, _badgeLandscapeOffsetY);}else{  //竖屏状态_badgeView.badgePositionAdjustment = CGPointMake(-_badgeOffsetX, _badgeOffsetY);}_badgeView.badgeStrokeWidth = 0.2;_badgeView.badgeText  = _badgeText;//清除旋转状态self.orientation = UIDeviceOrientationUnknown;}
}

关于使用

初始化tabbar
-(void)setupTabbar{TYTabBar *tabbar = [[TYTabBar alloc] init];self.tyTabbar = tabbar;self.tyTabbar.realDelegate = self;//给tabbar设置内容//准备数据NSArray *arr = @[@"竞猜", @"赛事", @"发现", @"优惠", @"我的"];                //titleNSArray *animationImageArr = @[self.quizAnimationImages, self.matchAnimationImages, @[], self.discountAnimationImages, self.mineAnimationImages];NSArray *barImages = @[@[@"quiz_normal", @"quiz_selected"],                //按钮默认图片和选中后图片@[@"match_normal", @"match_selected"],@[@"discovery_normal", @"discovery_selected"],@[@"discount_normal", @"discount_selected"],@[@"mine_normal", @"mine_selected"],];NSArray *anmations = @[@(TYBarItemAnimationTypeFrames),@(TYBarItemAnimationTypeFrames),@(TYBarItemAnimationTypeRotate),@(TYBarItemAnimationTypeFrames),@(TYBarItemAnimationTypeFrames)];NSMutableArray *datas = [NSMutableArray array];for (int i = 0;  i < 5; i++) {//0. 根据需求选择填写对应的内容//1. 每个按钮都可以单独设置图片 文字 动画效果(暂时只有4种效果)等//2. 如果点击后不需要帧动画 images可以传nil//3. 如果所有按钮都是统一动画,AnimationType 默认传一个值就可以了//4. title为BarItem显示的文字//5. nomalImage selectdImage 为BarItem选中和非选中的图片 选中和非选中按钮颜色在TYTabBar中配置TYBarItemModel *model = [[TYBarItemModel alloc] initWithTitle:arr[i] images:animationImageArr[i] normalImage:barImages[i][0] selectedImage:barImages[i][1] AnimationType:[anmations[i] integerValue]];[datas addObject:model];}//初始化tabbar数据[self.tyTabbar loadItemsWithData:datas defaultSelect:2];//替换系统的tabbar[self setValue:tabbar forKeyPath:@"tabBar"];//如果希望TabbarItem重复点击都有动画效果 则需要设置canRepeatClick= YES 默认为NOself.tyTabbar.canRepeatClick = YES;//设置角标[self.tyTabbar badgeText:@"9" forIndex:0];[self.tyTabbar badgeText:@"." forIndex:3];}
初始化控制器
- (void) loadViewControllers {//这里的title是导航栏的标题ViewController* homepageVC = [[ViewController alloc] init];[self setUpOneChildVcWithVc:homepageVC  title:@"竞猜"];ViewController * classifyVC = [[ViewController alloc] init];[self setUpOneChildVcWithVc:classifyVC  title:@"赛事"];ViewController* shoppingCartVC = [[ViewController alloc] init];[self setUpOneChildVcWithVc:shoppingCartVC  title:@"发现"];ViewController * searchVC = [[ViewController alloc] init];[self setUpOneChildVcWithVc:searchVC  title:@"优惠"];ViewController* personalCenterVC = [[ViewController alloc] init];[self setUpOneChildVcWithVc:personalCenterVC  title:@"我的"];
}- (void)setUpOneChildVcWithVc:(UIViewController *)Vc title:(NSString *)title {UINavigationController *nav = [[UINavigationController alloc] initWithRootViewController:Vc];Vc.navigationItem.title = title;[self addChildViewController:nav];
}
tabbar代理方法使用
-(void)tabBar:(TYTabBar *)tabbar clickIndex:(NSInteger)index{[self setSelectedIndex:index];
}-(void)tabBar:(TYTabBar *)tabBar doubleClick:(NSInteger)index{NSLog(@"第%zi个Item被双击",index);//根据选中的Inex,拿到对应的控制器然后让控制器刷新数据UINavigationController *naviVC = (UINavigationController *)self.selectedViewController;ViewController *dpVc = (ViewController *)naviVC.viewControllers.firstObject;[dpVc reloadColor];
}

更多详细使用参考demo中代码

版权归tinych,qqcc1388所有,转载请标注转载来源:http://www.cnblogs.com/qqcc1388/p/7421633.html

参考来源:

JSBadgeView https://github.com/JaviSoto/JSBadgeView
CYLTabBarController https://github.com/ChenYilong/CYLTabBarController

转载于:https://www.cnblogs.com/qqcc1388/p/7421633.html

这篇关于iOS 开源一个高度可定制支持各种动画效果,支持单击双击,小红点,支持自定义不规则按钮的tabbar...的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/227379

相关文章

定价129元!支持双频 Wi-Fi 5的华为AX1路由器发布

《定价129元!支持双频Wi-Fi5的华为AX1路由器发布》华为上周推出了其最新的入门级Wi-Fi5路由器——华为路由AX1,建议零售价129元,这款路由器配置如何?详细请看下文介... 华为 Wi-Fi 5 路由 AX1 已正式开售,新品支持双频 1200 兆、配有四个千兆网口、提供可视化智能诊断功能,建

前端原生js实现拖拽排课效果实例

《前端原生js实现拖拽排课效果实例》:本文主要介绍如何实现一个简单的课程表拖拽功能,通过HTML、CSS和JavaScript的配合,我们实现了课程项的拖拽、放置和显示功能,文中通过实例代码介绍的... 目录1. 效果展示2. 效果分析2.1 关键点2.2 实现方法3. 代码实现3.1 html部分3.2

java获取图片的大小、宽度、高度方式

《java获取图片的大小、宽度、高度方式》文章介绍了如何将File对象转换为MultipartFile对象的过程,并分享了个人经验,希望能为读者提供参考... 目China编程录Java获取图片的大小、宽度、高度File对象(该对象里面是图片)MultipartFile对象(该对象里面是图片)总结java获取图片

SpringBoot定制JSON响应数据的实现

《SpringBoot定制JSON响应数据的实现》本文主要介绍了SpringBoot定制JSON响应数据的实现,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们... 目录前言一、如何使用@jsonView这个注解?二、应用场景三、实战案例注解方式编程方式总结 前言

CSS自定义浏览器滚动条样式完整代码

《CSS自定义浏览器滚动条样式完整代码》:本文主要介绍了如何使用CSS自定义浏览器滚动条的样式,包括隐藏滚动条的角落、设置滚动条的基本样式、轨道样式和滑块样式,并提供了完整的CSS代码示例,通过这些技巧,你可以为你的网站添加个性化的滚动条样式,从而提升用户体验,详细内容请阅读本文,希望能对你有所帮助...

vue基于ElementUI动态设置表格高度的3种方法

《vue基于ElementUI动态设置表格高度的3种方法》ElementUI+vue动态设置表格高度的几种方法,抛砖引玉,还有其它方法动态设置表格高度,大家可以开动脑筋... 方法一、css + js的形式这个方法需要在表格外层设置一个div,原理是将表格的高度设置成外层div的高度,所以外层的div需要

最好用的WPF加载动画功能

《最好用的WPF加载动画功能》当开发应用程序时,提供良好的用户体验(UX)是至关重要的,加载动画作为一种有效的沟通工具,它不仅能告知用户系统正在工作,还能够通过视觉上的吸引力来增强整体用户体验,本文给... 目录前言需求分析高级用法综合案例总结最后前言当开发应用程序时,提供良好的用户体验(UX)是至关重要

基于Python实现PDF动画翻页效果的阅读器

《基于Python实现PDF动画翻页效果的阅读器》在这篇博客中,我们将深入分析一个基于wxPython实现的PDF阅读器程序,该程序支持加载PDF文件并显示页面内容,同时支持页面切换动画效果,文中有详... 目录全部代码代码结构初始化 UI 界面加载 PDF 文件显示 PDF 页面页面切换动画运行效果总结主

React实现原生APP切换效果

《React实现原生APP切换效果》最近需要使用Hybrid的方式开发一个APP,交互和原生APP相似并且需要IM通信,本文给大家介绍了使用React实现原生APP切换效果,文中通过代码示例讲解的非常... 目录背景需求概览技术栈实现步骤根据 react-router-dom 文档配置好路由添加过渡动画使用

SpringBoot 自定义消息转换器使用详解

《SpringBoot自定义消息转换器使用详解》本文详细介绍了SpringBoot消息转换器的知识,并通过案例操作演示了如何进行自定义消息转换器的定制开发和使用,感兴趣的朋友一起看看吧... 目录一、前言二、SpringBoot 内容协商介绍2.1 什么是内容协商2.2 内容协商机制深入理解2.2.1 内容