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里做判斷的。等等一些小問題 就不一一列舉了。****

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容