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 = @"http://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里做判断的。等等一些小问题 就不一一列举了。****

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 156,265评论 4 359
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 66,274评论 1 288
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 106,087评论 0 237
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 43,479评论 0 203
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 51,782评论 3 285
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,218评论 1 207
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,594评论 2 309
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,316评论 0 194
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 33,955评论 1 237
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,274评论 2 240
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 31,803评论 1 255
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,177评论 2 250
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 32,732评论 3 229
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 25,953评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,687评论 0 192
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,263评论 2 267
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,189评论 2 258

推荐阅读更多精彩内容