目錄:
- 1、兩種框架的介紹
- 2、微信主流框架的實(shí)現(xiàn)思路
- 3、微信主流框架的代碼實(shí)現(xiàn)
- 4、微博主流框架的實(shí)現(xiàn)思路
- 5、微博主流框架的代碼實(shí)現(xiàn)
- 6、總結(jié)
- 7、Demo下載
介紹
實(shí)際開(kāi)發(fā)中,我們常會(huì)見(jiàn)到兩種主流框架,一種類(lèi)似于微信,UIWindow的根rootViewController為UITabBarController,然后調(diào)用addChildViewController(繼承自UIViewController)添加子控制器。然后實(shí)現(xiàn)控制器的跳轉(zhuǎn)。
簡(jiǎn)述下點(diǎn)擊UITabBarController的UITabBar切換控制器的原理:
點(diǎn)擊UITabBarController上的UITabBar跳轉(zhuǎn)控制器的原理是:
很多人未曾注意到UIViewController有個(gè)容器屬性,可以添加一組子控制器。
@property(nonatomic,readonly) NSArray<__kindof UIViewController *> *childViewControllers NS_AVAILABLE_IOS(5_0);
當(dāng)然也可以通過(guò)如下方法添加子控制器
- (void)addChildViewController:(UIViewController *)childController NS_AVAILABLE_IOS(5_0);
UITabBarController繼承自UIViewController,當(dāng)然也會(huì)繼承這個(gè)屬性和方法。
UITabBarController的代理協(xié)議UITabBarControllerDelegate中有- (void)tabBarController:(UITabBarController *)tabBarController didSelectViewController:(UIViewController *)viewController;這個(gè)方法,點(diǎn)擊UITabBar時(shí),會(huì)將數(shù)組中的對(duì)應(yīng)的UIViewController取出放在當(dāng)前界面并顯示。
當(dāng)點(diǎn)擊UITabBarController上的UITabBar時(shí),會(huì)實(shí)現(xiàn)這個(gè)代理方法并完成控制器的切換。
一、微信主流框架的搭建
1、微信主流框架的實(shí)現(xiàn)思路
微信的UITabBarController和系統(tǒng)的樣式相同,實(shí)現(xiàn)原理也一樣,所以在此主要講解下控制器之間代碼的實(shí)現(xiàn)思路和封裝。
- 1.在A(yíng)ppDelegate中,將window的rootViewController設(shè)置為帶有UITabBarController的導(dǎo)航控制器;
- 2.創(chuàng)建子控制器,設(shè)置子控制器的title,image,selectedImage等屬性
- 3.設(shè)置子控制器的導(dǎo)航控制器,并添加到childViewController中
2、微信主流框架的代碼實(shí)現(xiàn)
1. 在A(yíng)ppDelegate中,將window的rootViewController設(shè)置為帶有UITabBarController的導(dǎo)航控制器;
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
//類(lèi)似微信的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. 創(chuàng)建子控制器,設(shè)置子控制器的title,image,selectedImage等屬性
/**
* 初始化一個(gè)子控制器
*
* @param childVc 需要初始化的子控制器
* @param title 標(biāo)題
* @param imageName 圖標(biāo)
* @param selectedImageName 選中的圖標(biāo)
*/
- (void)addChildViewController:(UIViewController *)childVc title:(NSString *)title imageName:(NSString *)imageName selectedImageName:(NSString *)selectedImageName
{
// 1.設(shè)置控制器的屬性
childVc.title = title;
// 設(shè)置圖標(biāo)
childVc.tabBarItem.image = [UIImage imageNamed:imageName];
// 設(shè)置選中的圖標(biāo)
childVc.tabBarItem.selectedImage = [UIImage imageNamed:selectedImageName];
// 2.包裝一個(gè)導(dǎo)航控制器
UINavigationController *nav = [[UINavigationController alloc] initWithRootViewController:childVc];
[self addChildViewController:nav];
}
3. 設(shè)置子控制器的導(dǎo)航控制器,并添加到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切換是調(diào)用了代理方法,取出數(shù)組中對(duì)應(yīng)的控制器,然后顯示。
但點(diǎn)擊微博的中間的加號(hào)按鈕,彈出pop動(dòng)畫(huà)的界面,而不是子控制器。
那怎么實(shí)現(xiàn)這個(gè)功能呢?
嚴(yán)格來(lái)說(shuō),有UITabBarController有n個(gè)子控制器,下面的UITabBar就有n個(gè)UITabBarItem。但我們只有4個(gè)控制器,下面卻有5個(gè)UITabBarItem怎么辦?
顯然系統(tǒng)的UITabBar不好用,那就只能重寫(xiě)了。
所以我們自定義一個(gè)UITabBar類(lèi)的新類(lèi)GBTabBar。
由于UITabBar繼承自UIView,所以我們只要把中間的加號(hào)按鈕定義為一個(gè)button,然后通過(guò)在GBTabBar中[self addSubview:button]就可以了。
然后實(shí)現(xiàn)按鈕的點(diǎn)擊事件,并通過(guò)代理(或者block等方式)將點(diǎn)擊方法傳到UITabBarController中。
但注意,由于系統(tǒng)的UITabBarItem的會(huì)平分整個(gè)UITabBar,所以添加完button之后,我們需要重寫(xiě)每一個(gè)UITabBarItem的尺寸。
1、微博主流框架的實(shí)現(xiàn)思路
微信的UITabBarController和系統(tǒng)的樣式相同,實(shí)現(xiàn)原理也一樣,所以在此主要講解下控制器之間代碼的實(shí)現(xiàn)思路和封裝。
- 1.在A(yíng)ppDelegate中,將window的rootViewController設(shè)置為帶有UITabBarController的導(dǎo)航控制器;
- 2.創(chuàng)建子控制器,設(shè)置子控制器的title,image,selectedImage等屬性
- 3.設(shè)置子控制器的導(dǎo)航控制器,并添加到childViewController中
- 4.自定義新的UITabBar,然后在UITabBar上添加中間的加號(hào)按鈕
- 5.重寫(xiě)layoutSubviews,完成布局。
- 6.實(shí)現(xiàn)點(diǎn)擊事件,并定義代理方法,將代理方法傳至UITabBarController中
2、微博主流框架的代碼實(shí)現(xiàn)
1. 在A(yíng)ppDelegate中,將window的rootViewController設(shè)置為帶有UITabBarController的導(dǎo)航控制器;
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
//類(lèi)似微信的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. 創(chuàng)建子控制器,設(shè)置子控制器的title,image,selectedImage等屬性
/**
* 初始化一個(gè)子控制器
*
* @param childVc 需要初始化的子控制器
* @param title 標(biāo)題
* @param imageName 圖標(biāo)
* @param selectedImageName 選中的圖標(biāo)
*/
- (void)addChildViewController:(UIViewController *)childVc title:(NSString *)title imageName:(NSString *)imageName selectedImageName:(NSString *)selectedImageName
{
// 1.設(shè)置控制器的屬性
childVc.title = title;
// 設(shè)置圖標(biāo)
childVc.tabBarItem.image = [UIImage imageNamed:imageName];
// 設(shè)置選中的圖標(biāo)
childVc.tabBarItem.selectedImage = [UIImage imageNamed:selectedImageName];
// 2.包裝一個(gè)導(dǎo)航控制器
UINavigationController *nav = [[UINavigationController alloc] initWithRootViewController:childVc];
[self addChildViewController:nav];
}
3. 設(shè)置子控制器的導(dǎo)航控制器,并添加到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上添加中間的加號(hào)按鈕,并重寫(xiě)layoutSubviews,完成布局
#import "GBTabBar.h"
@interface GBTabBar ()
@property(nonatomic,strong) UIButton *customButton; //自定義加號(hào)按鈕
@end
@implementation GBTabBar
- (instancetype)initWithFrame:(CGRect)frame {
self = [super initWithFrame: frame];
if (self) {
// 添加一個(gè)加號(hào)按鈕
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];
//先設(shè)置中間按鈕的位置
self.customButton.center = CGPointMake(self.frame.size.width / 2, self.frame.size.height / 2);
//計(jì)算每個(gè)按鈕的寬度
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. 實(shí)現(xiàn)點(diǎn)擊事件,并定義代理方法,將代理方法傳至UITabBarController中
// GBTabBar.h文件中
#import <UIKit/UIKit.h>
//custom delegate
@class GBTabBar;
@protocol GBTabBarDelegate <NSObject>
@optional
- (void)tabBarDidClickPlusButton:(GBTabBar *)tabBar;
@end
@interface GBTabBar : UITabBar
//此處代理名字不能為delegate,因?yàn)闀?huì)和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];
}
}
文末總結(jié):
在我認(rèn)為,寫(xiě)技術(shù)博客,兩種方式會(huì)尤low:
- 從不結(jié)合實(shí)際需求,全篇大段的copy概念性知識(shí)點(diǎn),不講自己的理解的很low;
- 大段的copy代碼,只做代碼表層級(jí)別的注釋說(shuō)明,不講解實(shí)現(xiàn)原理和思路的更low;
以上兩種技術(shù)博客極少需要?jiǎng)幽X,寫(xiě)作成本很低。
因?yàn)檎迟N大段純概念知識(shí)點(diǎn),不建立在實(shí)際使用場(chǎng)景下很難形象理解,加深記憶;
大篇幅粘貼純代碼可以說(shuō)純了碰到實(shí)際需求,解決淺層問(wèn)題,讀者看了很難舉一反三;
當(dāng)然,也并非說(shuō)無(wú)用,只是說(shuō)用處不大,見(jiàn)效甚微而且只是無(wú)根。
所以我把這類(lèi)博客歸結(jié)為無(wú)根知識(shí)。
所以也希望讀者在看作者的文章時(shí),多帶思考。很多知識(shí)點(diǎn)是代入式的講解,希望能幫你構(gòu)建自己的知識(shí)網(wǎng)羅。
我不做無(wú)根的作者,你也不要做淺層的讀者。
如有錯(cuò)誤歡迎指出,文畢,程序員注定不能做一個(gè)孤獨(dú)的勇士,也歡迎大家加微信號(hào)bin5211bin學(xué)習(xí)交流。
點(diǎn)擊下載Demo:
Demo下載
- 代碼說(shuō)明,默認(rèn)是微博類(lèi)型框架,切換微信控制器只需要在A(yíng)ppDelegate中將navagationController的rootViewController改為weChatVc即可。