IOS开发入门iOS 根据后台设置tabbar (自定义tabbar)
白羽 2019-05-21 来源 :网络 阅读 423 评论 0

摘要:本文将带你了解IOS开发入门iOS 根据后台设置tabbar (自定义tabbar),希望本文对大家学IOS有所帮助。

    本文将带你了解IOS开发入门iOS 根据后台设置tabbar (自定义tabbar),希望本文对大家学IOS有所帮助。


IOS开发入门iOS 根据后台设置tabbar (自定义tabbar)


最近公司让我们把APP的tabbar按钮写活,什么意思呢?就是读取后台数据,后台让你把哪个controller设置成tabbar,你就得在本地把哪个controller写成tabbar。总结为一句话:读取后台数据,设置tabbar。是不是看到这里懵逼了。是的当我听到这个消息的时候我也懵逼了。因为我所见过的所有用原生写的主流app,人家的tabbar都是写死的。但是老大说了,客户有这样的需求,必须实现。我只能硬着头皮去尝试了,而且我们的app里还有抽屉,抽屉和自定义的tabbar放在一起,可想而知会炸了,果然这东西花了我半个月时间。言归正传,下面我来介绍,如何根据后台数据写你的tabbar。
   
   对了提一个小建议:做项目的时候 最好建一个 基类,创建其他的控制器继承这个基类 ,基类很好用,也很方便。
   
   1.遇到的问题:根据后台数据设定tabbar 那么这个数据请求肯定要写在APPdelegate 的 -  (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary  *)launchOptions 方法里 。只有拿到数据我们才能去设置tabbar 而 根视图 要设置成第一个tabbar的controller 且必须在-  (BOOL)application:(UIApplication *)application  didFinishLaunchingWithOptions:(NSDictionary *)launchOptions 方法里设定,不在该方法设定会报错。  那数据请求(我用的是ASI)是异步的,所以肯定会报错了。
   
   解决的方法是:在
   - (BOOL)application:(UIApplication *)application  didFinishLaunchingWithOptions:(NSDictionary *)launchOptions { }
   方法里先设置一个空白的controller做为根视图,等到数据请求完成之后,根据后台数据设置tabbar  ,再把第一个tabbar重新设置成根视图(注意:写在主线程里)。如果后台给的数据没有tabbar,那就把抽屉的第一条数据所对应的controller设置成根视图(这时候只有抽屉没有tabbar)。至于如何判断tabbar,那需要你和后台约定好字段,根据约定的字段去判断了,代码:
   
   
   解释: myfri就是 你判断后,得到要写成tabbar的conroller
   
   UIViewController *conTroll = myfri;
   
   UINavigationController *mainNAV = [[UINavigationController alloc]  initWithRootViewController:conTroll];
   
   //存 未选中
   NSString *myStr = [NSString stringWithFormat:@"%@",[dicc  objectForKey:@"app_btn_icon"]];
   NSString *str = [NSString stringWithFormat:@"tabbarIma%d@2x.png",i];
   [self mySaveImage:myStr andNumber:str];
   
   NSString *fullPath = [[NSHomeDirectory()  stringByAppendingPathComponent:@"Documents"]  stringByAppendingPathComponent:str];
   
   
   //存 选中
   NSString *myStr1 = [NSString stringWithFormat:@"%@",[dicc  objectForKey:@"app_btn_click_icon"]];
   
   NSString *str1 = [NSString  stringWithFormat:@"tabbarImano%d@2x.png",i];
   
   NSString *fullPath1 = [[NSHomeDirectory()  stringByAppendingPathComponent:@"Documents"]  stringByAppendingPathComponent:str1];
   
   [self mySaveImage:myStr1 andNumber:str1];
   
   //取
   UIImage *savedImage = [[UIImage alloc] initWithContentsOfFile:fullPath];
   UIImage *savedImage1 = [[UIImage alloc]  initWithContentsOfFile:fullPath1];
   
   // tabbar 图片赋值
   mainNAV.tabBarItem.selectedImage = [savedImage1  imageWithRenderingMode:UIImageRenderingModeAutomatic];
   mainNAV.tabBarItem.image = [savedImage  imageWithRenderingMode:UIImageRenderingModeAutomatic];
   
   NSLog(@"1111的%@",savedImage);
   
   //tabbar 字体大小
   [mainNAV.tabBarItem setTitleTextAttributes:[NSDictionary dictionaryWithObjectsAndKeys:
   [UIFont fontWithName:@"Helvetica" size:12.0],  NSFontAttributeName, nil]
   forState:UIControlStateNormal];
   
   
   mainNAV.tabBarItem.title = [dicc objectForKey:@"app_btn_name"];
   
   mainNAV.tabBarItem.tag = 2222+i ;
   
   [arrtab addObject:mainNAV];
   
   
   // 我自己定义的tabbar
   XTabbarViewController *tabbar = [[XTabbarViewController alloc]init];
   
   tabbar.tabBar.tintColor = UIColorFromRGBA(0xe13836);
   
   tabbar.viewControllers = arrtab;
   
   self.sideViewController = [[YRSideViewController alloc] init]; //  YRSideViewController 是抽屉的三方 自己百度下载 这里我把它定义成了属性
   
   // 用于 第一个tabbar 的数据切换 起始值为 0 表示下面的第一个tabbr 显示tabbar自己的数据,为 1  时显示左侧第一个栏目数据
   [[NSUserDefaults standardUserDefaults] setObject:@"0"  forKey:@"cutTabbar"]; //这个在左侧第一栏和tabbar之间切换时用
   
   UINavigationController *nav = [[UINavigationController alloc]  initWithRootViewController:self.sideViewController];
   
   self.sideViewController.leftViewShowWidth = Width * 2.0 / 5.0 ;
   
   self.sideViewController.needSwipeShowMenu = NO;
   
   nav.navigationBarHidden = YES;
   
   self.sideViewController.rightViewShowWidth = 300;
   
   self.sideViewController.rootViewController = tabbar; //设置抽屉的根试图
   
   self.sideViewController.leftViewController = leftVC; //设置 左侧抽屉的controller  leftVC里面写的是tableview 抽屉上一栏一栏的其实是这个tableview的cell
   
   self.sideViewController.needSwipeShowMenu = NO;//默认开启的可滑动展示
   
   self.window.rootViewController = nav;; //把上面的nav设置成根视图
   
   2.遇到的问题: 假如第一个tabbar对应的controller  和抽屉的第一栏所对应的controller不一样,那么抽屉的第一栏所对应的controller是无法显示的, 也就是说你点击左侧抽屉第一栏,永远显示的是第一个tabbar所对应的controller  这个问题困惑了我好久,一直找不到解决的办法,最后试了各种方法最终解决了。
   
   解决的方法:创建一个controller做为父视图控制器,把它作为第一个tabbar 把左侧第一栏所对应的controller 和  第一个tabbar所对应的controller 作为子视图控制器 添加到父视图控制器上 代码:
   
   [self addChildViewController:self.tabbarVC]; //self.tabbarVC  表示的tabbar的controller
   
   [self.view addSubview:self.tabbarVC.view];
   
   self.currentVC = self.tabbarVC; // self.currentVC 表示的是当前显示的controller
   
   然后 在抽屉的第一栏的点击事件- (void)tableView:(UITableView *)tableView  didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
   // 点击左侧第一个 栏目 1 表示 切换下面的第一个tabbar
   [[NSUserDefaults standardUserDefaults] setObject:@"1"  forKey:@"cutTabbar"];
   [userDefaults synchronize];
   调用 [sideViewController hideSideViewController:YES]; 方法
   }
   在抽屉三方的 - (void)hideSideViewController:(BOOL)animated{ “发通知 ”};
   发消息通知 父视图控制器接收到通知 就去判断 父视图当前显示的视图是不是左侧的 controller 不是就切换成左侧controller  。
   那如何切回原来tabbar的 controller呢? 很简单,同样在我们自定义的XTabbarViewController类的 的点击事件里  发消息通知 父视图控制器接收到通知 判断当前显示的controller 是不是tabbar 对应的controller ,不是就切换。父视图  消息中心执行代码:
   -(void)myNotification:(NSNotification *)not
   {
   NSLog(@"childViewControllers === %@",self.childViewControllers);
   NSDictionary *ddd =not.object;
   NSLog(@"取出 几 ? %@",not.object);
   
   //0 代表 点击的是tabbar 1代表点击的是 左侧的栏目
   
   if ([ddd[@"key"] integerValue] == 0) {
   
   NSLog(@"self.leftType == %@",self.leftType);
   
   NSString * childType = [NSString  stringWithFormat:@"%@",[self.childViewControllers[0] class]]  ;
   
   if ([childType isEqualToString:self.leftType]) {
   
   self.tabBarController.tabBar.tintColor = UIColorFromRGBA(0xe13836);;  //切换成tabbar的颜色
   
   [self replaceController:self.leftVC newController:self.tabbarVC];
   
   }else{
   
   }
   }else if([ddd[@"key"] integerValue] == 1){
   
   NSString *nub = [[NSUserDefaults standardUserDefaults]  objectForKey:@"cutTabbar"];
   
   NSLog(@"cutTabbar == %@",nub);
   if ([nub integerValue] == 1) {
   
   NSString * childType = [NSString stringWithFormat:@"%@",[self.childViewControllers[0]  class]] ;
   
   self.tabBarController.tabBar.tintColor = UIColorFromRGBA(0x999999);  //显示的是左侧抽屉controller 切换成回颜色
   
   if ([childType isEqualToString:self.tabbarType]) {
   
   [self replaceController:self.tabbarVC newController:self.leftVC];
   }else{
   
   NSLog(@"不一样");
   
   }
   
   // 切换了第一个tabbar的数据后 重置这个值 否则点击回到左侧抽屉时,即便不点击左侧第一个栏目也会切换成左侧第一个栏目
   [[NSUserDefaults standardUserDefaults] setObject:@"0"  forKey:@"cutTabbar"];
   
   }
   }else{
   self.tabBarController.tabBar.tintColor = UIColorFromRGBA(0xe13836);
   }
   }
   // 切换各个标签内容
   - (void)replaceController:(UIViewController *)oldController  newController:(UIViewController *)newController
   {
   /**
   * 着重介绍一下它
   *  transitionFromViewController:toViewController:duration:options:animations:completion:
   * fromViewController 当前显示在父视图控制器中的子视图控制器
   * toViewController 将要显示的姿势图控制器
   * duration 动画时间(这个属性,old friend 了 O(∩_∩)O)
   * options 动画效果(渐变,从下往上等等,具体查看API)
   * animations 转换过程中得动画
   * completion 转换完成
   */
   
   if ([newController isKindOfClass:[oldController class]] ) {
   
   }else{
   
   [self addChildViewController:newController];
   
   [self transitionFromViewController:oldController  toViewController:newController duration:0.5  options:UIViewAnimationOptionTransitionCrossDissolve animations:nil completion:^(BOOL  finished) {
   
   if (finished) {
   
   [newController didMoveToParentViewController:self];
   [oldController willMoveToParentViewController:nil];
   [oldController removeFromParentViewController];
   self.currentVC = newController;
   
   }else{
   
   self.currentVC = oldController;
   
   }
   }];
   }
   }
   
   
   
   3.遇到的问题: 我们都知道tabbar的图片设置是 在本地放几张图片,名字要写成“xxx@2.png” 用 [UIImage  imageNamed:] 去设置,为什么要把名字写成这样呢?自己百度一下。然而我们的tabbar根据后台设定了,那他的图片不可能放到我们本地吧,所以要用后台给的图片网址去设置了。这个问题也是搞了好久,我用【UIImage  imageWithData:】,然后处理了一下大小 图片是可以显示上去,但是一直很模糊。最后想到用沙盒存储,终于解决了这个问题 。存的 代码:
   
   NSString *str = [NSString  stringWithFormat:@"tabbarIma%d@2x.png",i];// i表示的是第几个tabbar
   
   NSString *fullPath = [[NSHomeDirectory()  stringByAppendingPathComponent:@"Documents"]stringByAppendingPathComponent:str];
   
   BOOL haveImageFile = [Tools toolsOfHasLibraryPathName:fullPath];
   NSLog(@"fullPath == %@ 本地有路径吗 =  %hhd",fullPath,haveImageFile);
   
   
   if (!haveImageFile) {
   [self mySaveImage:myStr andNumber:str];
   
   }
   
   -(void)mySaveImage:(NSString *)urlString andNumber:(NSString *)strnum
   {
   // NSString *urlString =  @"https://rmt.oss-cn-hangzhou.aliyuncs.com/public/icontest02.png";
   NSData *data = [NSData dataWithContentsOfURL:[NSURL  URLWithString:urlString]];
   UIImage *image = [UIImage imageWithData:data]; // 取得图片
   
   // 本地沙盒目录
   // 得到本地沙盒中名为"MyImage"的路径,"MyImage"是保存的图片名
   // NSString *strnum = [NSString  stringWithFormat:@"%@@2x.png",number];
   NSString *imageFilePath = [[NSHomeDirectory()  stringByAppendingPathComponent:@"Documents"]  stringByAppendingPathComponent:strnum];
   // 将取得的图片写入本地的沙盒中,其中0.5表示压缩比例,1表示不压缩,数值越小压缩比例越大
   NSLog(@"图片路径 == %@",imageFilePath);
   BOOL success = [UIImagePNGRepresentation(image) writeToFile:imageFilePath  atomically:YES];
   if (success){
   NSLog(@"写入本地成功");
   
   }
   }
   
   取图片的代码:
   
   UIImage *savedImage = [[UIImage alloc] initWithContentsOfFile:fullPath];  //未选中图片
   
   UIImage *savedImage1 = [[UIImage alloc] initWithContentsOfFile:fullPath1];  //选中图片
   
   mainNAV.tabBarItem.selectedImage = [savedImage1  imageWithRenderingMode:UIImageRenderingModeAutomatic];
   
   mainNAV.tabBarItem.image = [savedImage  imageWithRenderingMode:UIImageRenderingModeAutomatic];
   
   其实利用沙盒 ,无非就是为了存储的时候可以给图片 赋一个"xxx@2x"的名字
   
   
   4.遇到的问题: 消息推送的跳转
   
   以前写死的tabbar的app里 假如你把消息推送的跳转写在 第一个tabbar的controller上 ,那你的当前界面如果在其他tabbar里收到了通知,你点击查看,是不是跳转不过去,除非你在点击事件里改变tabbar的索引为0。  那我们的tabbar都写活了,你都不知道哪个controller要被设置成第一个tabbar,所以这种方法无法解决 。找了一些资料  看了看,发现基类可以解决,而且都不需要去改变tabbar的索引,试了一下果然可以。我顿时对基类这个东西刮目相看了。
   
   解决的方法:
   在基类里 写:
   
   -(void)viewWillAppear:(BOOL)animated
   {
   [super viewWillAppear:animated];
   [[NSNotificationCenter defaultCenter] addObserver:self  selector:@selector(notificationToNewsDetail:)  name:@"skipToNewsDetail" object:nil];
   }
   
   -(void)viewDidDisappear:(BOOL)animated{
   [super viewWillDisappear:animated];
   [[NSNotificationCenter defaultCenter] removeObserver:self  name:@"skipToNewsDetail" object:nil];
   }
   
   
   
   - (void)notificationToNewsDetail:(NSNotification *)noti
   {
   // [self tabbarchange];
   
   
   NSMutableDictionary *dic =(NSMutableDictionary *)noti.userInfo;
   
   
   NSString *myKey =[NSString stringWithFormat:@"%@",[ dic  objectForKey:@"info_key"]];
   
   NSLog(@"推送过来的,东西%@",dic);
   
   if (STRING_ISNIL(myKey)) {
   
   }
   
   else{
   
   NewsJSViewController * newsVC = [[NewsJSViewController alloc]init];
   newsVC.keyString = myKey;
   
   newsVC.typeString=[NSString stringWithFormat:@"%@",[dic  objectForKey:@"info_class"]];
   newsVC.dictionary=dic;
   
   newsVC.hidesBottomBarWhenPushed = YES;
   
   [self.navigationController pushViewController:newsVC animated:YES];
   }
   }
   
   发通知的地方 当然是appdelegate 的
   - (void)application:(UIApplication *)application  didReceiveRemoteNotification:(NSDictionary *)userInfo{
   userInfo 里面是推送过来的数据 你可以在这里写一个 alertController 在他的确定时间里 写你的发送通知的代码。
   }
   
   5. 遇到的问题 里面还会遇到一些小的问题,比如每一个controller的 布局问题, 如果这个controller被设置成tabbar了  那么它里面的 tableview或者collectionView 的fram 的高度是不是 要减去49  。这个需要在controller里做判断的。等等一些小问题 就不一一列举了。****
   

本文由职坐标整理并发布,希望对同学们有所帮助。了解更多详情请关注职坐标移动开发之IOS频道!

本文由 @白羽 发布于职坐标。未经许可,禁止转载。
喜欢 | 0 不喜欢 | 0
看完这篇文章有何感觉?已经有0人表态,0%的人喜欢 快给朋友分享吧~
评论(0)
后参与评论

您输入的评论内容中包含违禁敏感词

我知道了

助您圆梦职场 匹配合适岗位
验证码手机号,获得海同独家IT培训资料
选择就业方向:
人工智能物联网
大数据开发/分析
人工智能Python
Java全栈开发
WEB前端+H5

请输入正确的手机号码

请输入正确的验证码

获取验证码

您今天的短信下发次数太多了,明天再试试吧!

提交

我们会在第一时间安排职业规划师联系您!

您也可以联系我们的职业规划师咨询:

小职老师的微信号:z_zhizuobiao
小职老师的微信号:z_zhizuobiao

版权所有 职坐标-一站式IT培训就业服务领导者 沪ICP备13042190号-4
上海海同信息科技有限公司 Copyright ©2015 www.zhizuobiao.com,All Rights Reserved.
 沪公网安备 31011502005948号    

©2015 www.zhizuobiao.com All Rights Reserved

208小时内训课程