目錄:
- 1、兩種框架的介紹
- 2、微信主流框架的實現思路
- 3、微信主流框架的代碼實現
- 4、微博主流框架的實現思路
- 5、微博主流框架的代碼實現
- 6、總結
- 7、Demo下載
介紹
實際開發中,我們常會見到兩種主流框架,一種類似于微信,UIWindow的根rootViewController
為UITabBarController
,然后調用addChildViewController
(繼承自UIViewController)添加子控制器。然后實現控制器的跳轉。
簡述下點擊UITabBarController的UITabBar切換控制器的原理:
點擊UITabBarController上的UITabBar跳轉控制器的原理是:
很多人未曾注意到UIViewController
有個容器屬性,可以添加一組子控制器。
@property(nonatomic,readonly) NSArray<__kindof UIViewController *> *childViewControllers NS_AVAILABLE_IOS(5_0);
當然也可以通過如下方法添加子控制器
- (void)addChildViewController:(UIViewController *)childController NS_AVAILABLE_IOS(5_0);
UITabBarController繼承自UIViewController,當然也會繼承這個屬性和方法。
UITabBarController的代理協議UITabBarControllerDelegate
中有- (void)tabBarController:(UITabBarController *)tabBarController didSelectViewController:(UIViewController *)viewController;
這個方法,點擊UITabBar時,會將數組中的對應的UIViewController取出放在當前界面并顯示。
當點擊UITabBarController上的UITabBar時,會實現這個代理方法并完成控制器的切換。
一、微信主流框架的搭建
1、微信主流框架的實現思路
微信的UITabBarController和系統的樣式相同,實現原理也一樣,所以在此主要講解下控制器之間代碼的實現思路和封裝。
- 1.在AppDelegate中,將window的rootViewController設置為帶有UITabBarController的導航控制器;
- 2.創建子控制器,設置子控制器的title,image,selectedImage等屬性
- 3.設置子控制器的導航控制器,并添加到childViewController中
2、微信主流框架的代碼實現
1. 在AppDelegate中,將window的rootViewController設置為帶有UITabBarController的導航控制器;
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
//類似微信的UITabBarController
GBWeChatTabBarController *weChatVc = [[GBWeChatTabBarController alloc]init];
UINavigationController *nav = [[UINavigationController alloc]initWithRootViewController:weChatVc];
self.window = [[UIWindow alloc]initWithFrame:[UIScreen mainScreen].bounds];
self.window.rootViewController = nav;
[self.window makeKeyAndVisible];
return YES;
}
2. 創建子控制器,設置子控制器的title,image,selectedImage等屬性
/**
* 初始化一個子控制器
*
* @param childVc 需要初始化的子控制器
* @param title 標題
* @param imageName 圖標
* @param selectedImageName 選中的圖標
*/
- (void)addChildViewController:(UIViewController *)childVc title:(NSString *)title imageName:(NSString *)imageName selectedImageName:(NSString *)selectedImageName
{
// 1.設置控制器的屬性
childVc.title = title;
// 設置圖標
childVc.tabBarItem.image = [UIImage imageNamed:imageName];
// 設置選中的圖標
childVc.tabBarItem.selectedImage = [UIImage imageNamed:selectedImageName];
// 2.包裝一個導航控制器
UINavigationController *nav = [[UINavigationController alloc] initWithRootViewController:childVc];
[self addChildViewController:nav];
}
3. 設置子控制器的導航控制器,并添加到childViewController中
// 初始化所有的子控制器
- (void)setupAllChildViewControllers {
// 1.ONE
GBOneTableViewController *one = [[GBOneTableViewController alloc] init];
[self addChildViewController:one title:@"ONE" imageName:@"tabbar_home" selectedImageName:@"tabbar_home_selected"];
// 2.TWO
GBTwoTableViewController *two = [[GBTwoTableViewController alloc] init];
[self addChildViewController:two title:@"TWO" imageName:@"tabbar_message_center" selectedImageName:@"tabbar_message_center_selected"];
// 3.THREE
GBThreeTableViewController *three = [[GBThreeTableViewController alloc] init];
[self addChildViewController:three title:@"THREE" imageName:@"tabbar_discover" selectedImageName:@"tabbar_discover_selected"];
// 4.FOUR
GBFourTableViewController *four = [[GBFourTableViewController alloc] init];
[self addChildViewController:four title:@"FOUR" imageName:@"tabbar_profile" selectedImageName:@"tabbar_profile_selected"];
}
二、微博主流框架的搭建
但是微博就不同了。
回想一下,微信的UITabBarController切換是調用了代理方法,取出數組中對應的控制器,然后顯示。
但點擊微博的中間的加號按鈕,彈出pop動畫的界面,而不是子控制器。
那怎么實現這個功能呢?
嚴格來說,有UITabBarController有n個子控制器,下面的UITabBar就有n個UITabBarItem。但我們只有4個控制器,下面卻有5個UITabBarItem怎么辦?
顯然系統的UITabBar不好用,那就只能重寫了。
所以我們自定義一個UITabBar類的新類GBTabBar。
由于UITabBar繼承自UIView,所以我們只要把中間的加號按鈕定義為一個button,然后通過在GBTabBar中[self addSubview:button]
就可以了。
然后實現按鈕的點擊事件,并通過代理(或者block等方式)將點擊方法傳到UITabBarController中。
但注意,由于系統的UITabBarItem的會平分整個UITabBar,所以添加完button之后,我們需要重寫每一個UITabBarItem的尺寸。
1、微博主流框架的實現思路
微信的UITabBarController和系統的樣式相同,實現原理也一樣,所以在此主要講解下控制器之間代碼的實現思路和封裝。
- 1.在AppDelegate中,將window的rootViewController設置為帶有UITabBarController的導航控制器;
- 2.創建子控制器,設置子控制器的title,image,selectedImage等屬性
- 3.設置子控制器的導航控制器,并添加到childViewController中
- 4.自定義新的UITabBar,然后在UITabBar上添加中間的加號按鈕
- 5.重寫layoutSubviews,完成布局。
- 6.實現點擊事件,并定義代理方法,將代理方法傳至UITabBarController中
2、微博主流框架的代碼實現
1. 在AppDelegate中,將window的rootViewController設置為帶有UITabBarController的導航控制器;
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
//類似微信的UITabBarController
GBWeiboTabBarViewController *weiboVc = [[GBWeiboTabBarViewController alloc]init];
UINavigationController *nav = [[UINavigationController alloc]initWithRootViewController:weiboVc];
self.window = [[UIWindow alloc]initWithFrame:[UIScreen mainScreen].bounds];
self.window.rootViewController = nav;
[self.window makeKeyAndVisible];
return YES;
}
2. 創建子控制器,設置子控制器的title,image,selectedImage等屬性
/**
* 初始化一個子控制器
*
* @param childVc 需要初始化的子控制器
* @param title 標題
* @param imageName 圖標
* @param selectedImageName 選中的圖標
*/
- (void)addChildViewController:(UIViewController *)childVc title:(NSString *)title imageName:(NSString *)imageName selectedImageName:(NSString *)selectedImageName
{
// 1.設置控制器的屬性
childVc.title = title;
// 設置圖標
childVc.tabBarItem.image = [UIImage imageNamed:imageName];
// 設置選中的圖標
childVc.tabBarItem.selectedImage = [UIImage imageNamed:selectedImageName];
// 2.包裝一個導航控制器
UINavigationController *nav = [[UINavigationController alloc] initWithRootViewController:childVc];
[self addChildViewController:nav];
}
3. 設置子控制器的導航控制器,并添加到childViewController中
// 初始化所有的子控制器
- (void)setupAllChildViewControllers {
// 1.ONE
GBOneTableViewController *one = [[GBOneTableViewController alloc] init];
[self addChildViewController:one title:@"ONE" imageName:@"tabbar_home" selectedImageName:@"tabbar_home_selected"];
// 2.TWO
GBTwoTableViewController *two = [[GBTwoTableViewController alloc] init];
[self addChildViewController:two title:@"TWO" imageName:@"tabbar_message_center" selectedImageName:@"tabbar_message_center_selected"];
// 3.THREE
GBThreeTableViewController *three = [[GBThreeTableViewController alloc] init];
[self addChildViewController:three title:@"THREE" imageName:@"tabbar_discover" selectedImageName:@"tabbar_discover_selected"];
// 4.FOUR
GBFourTableViewController *four = [[GBFourTableViewController alloc] init];
[self addChildViewController:four title:@"FOUR" imageName:@"tabbar_profile" selectedImageName:@"tabbar_profile_selected"];
}
4. 自定義新的UITabBar,然后在UITabBar上添加中間的加號按鈕,并重寫layoutSubviews,完成布局
#import "GBTabBar.h"
@interface GBTabBar ()
@property(nonatomic,strong) UIButton *customButton; //自定義加號按鈕
@end
@implementation GBTabBar
- (instancetype)initWithFrame:(CGRect)frame {
self = [super initWithFrame: frame];
if (self) {
// 添加一個加號按鈕
UIButton *customButton = [UIButton buttonWithType:UIButtonTypeCustom];
[customButton setBackgroundImage:[UIImage imageNamed:@"tabbar_compose_button"] forState:UIControlStateNormal];
[customButton setBackgroundImage:[UIImage imageNamed:@"tabbar_compose_button_highlighted"] forState:UIControlStateHighlighted];
[customButton setImage:[UIImage imageNamed:@"tabbar_compose_icon_add"] forState:UIControlStateNormal];
[customButton setImage:[UIImage imageNamed:@"tabbar_compose_icon_add_highlighted"] forState:UIControlStateHighlighted];
customButton.bounds = CGRectMake(0, 0, customButton.currentBackgroundImage.size.width, customButton.currentBackgroundImage.size.height);
//添加方法
[customButton addTarget:self action:@selector(customButtonClick) forControlEvents:UIControlEventTouchUpInside];
[self addSubview:customButton];
self.customButton = customButton;
}
return self;
}
#pragma mark - system method
- (void)layoutSubviews {
[super layoutSubviews];
//先設置中間按鈕的位置
self.customButton.center = CGPointMake(self.frame.size.width / 2, self.frame.size.height / 2);
//計算每個按鈕的寬度
CGFloat tabBarButtonW = self.frame.size.width / 5;
CGFloat tabBarButtonIndex = 0;
for (UIView *child in self.subviews) {
Class class = NSClassFromString(@"UITabBarButton");
if ([child isKindOfClass:class]) {
child.frame = CGRectMake(tabBarButtonIndex * tabBarButtonW, 0, tabBarButtonW, self.frame.size.height);
tabBarButtonIndex++;
if (tabBarButtonIndex == 2) {
tabBarButtonIndex++;
}
}
}
}
5. 實現點擊事件,并定義代理方法,將代理方法傳至UITabBarController中
// GBTabBar.h文件中
#import <UIKit/UIKit.h>
//custom delegate
@class GBTabBar;
@protocol GBTabBarDelegate <NSObject>
@optional
- (void)tabBarDidClickPlusButton:(GBTabBar *)tabBar;
@end
@interface GBTabBar : UITabBar
//此處代理名字不能為delegate,因為會和UITabbar本身的delegate沖突
@property (nonatomic, weak) id<GBTabBarDelegate> myDelegate;
@end
// GBTabBar.m文件中
#pragma mark - custom method
- (void)customButtonClick {
NSLog(@"click");
//遵守代理
if ([self.myDelegate respondsToSelector:@selector(tabBarDidClickPlusButton:)]) {
[self.myDelegate tabBarDidClickPlusButton:self];
}
}
文末總結:
在我認為,寫技術博客,兩種方式會尤low:
- 從不結合實際需求,全篇大段的copy概念性知識點,不講自己的理解的很low;
- 大段的copy代碼,只做代碼表層級別的注釋說明,不講解實現原理和思路的更low;
以上兩種技術博客極少需要動腦,寫作成本很低。
因為粘貼大段純概念知識點,不建立在實際使用場景下很難形象理解,加深記憶;
大篇幅粘貼純代碼可以說純了碰到實際需求,解決淺層問題,讀者看了很難舉一反三;
當然,也并非說無用,只是說用處不大,見效甚微而且只是無根。
所以我把這類博客歸結為無根知識。
所以也希望讀者在看作者的文章時,多帶思考。很多知識點是代入式的講解,希望能幫你構建自己的知識網羅。
我不做無根的作者,你也不要做淺層的讀者。
如有錯誤歡迎指出,文畢,程序員注定不能做一個孤獨的勇士,也歡迎大家加微信號bin5211bin
學習交流。
點擊下載Demo:
Demo下載
- 代碼說明,默認是微博類型框架,切換微信控制器只需要在AppDelegate中將navagationController的rootViewController改為weChatVc即可。