最終效果圖:
BeyondViewController.m
//// BeyondViewController.m// 20_帥哥no微博//// Created by beyond on 14-8-3.// Copyright (c) 2014年 com.beyond. All rights reserved.// 這個就是主控制器,分為兩塊,下面是Dock欄,上面是顯示不同的子控制器的view,子控制器最好用導航控制器包裝一下,這樣子控制器就自帶了導航條,左按鈕,標題,右按鈕/* 無法點擊,或點擊 無響應的原因: userInteractionEnabled = NO; hidden = YES alpha 0) { // 0,先取出新的子控制器,如果 新的子控制器就是當前的這個控制器,直接返回 好嗎? UIViewController *childVC = [self childViewControllers][index]; if (childVC == _currentChildVC) return ; // 1,先移除先前的子控制器的view [_currentChildVC.view removeFromSuperview]; // 2,添加新的子控制器的view到主控制器的view childVC.view.frame = CGRectMake(0, 20, 320, 416); //log(@"self view --%@",NSStringFromCGRect(self.view.frame)); //log(@"childVC view --%@",NSStringFromCGRect(childVC.view.frame)); // 不會重復添加view,因為一旦發現重復添加某個view,就會將它置于最上面,最好是,先移除舊的view,再添加新的view [self.view addSubview:childVC.view ]; // 3,重要,必須更新當前的子控制器,為下次移除做準備 _currentChildVC = childVC; }}#pragma mark 創建所有的子控制器(一共5個,首面,消息,我,廣場,更多)- (void)createAllChildViewControllers{ // 1.遍歷欄目對象數組,批量創建所有的子控制器,并用導航控制器包裝,最后添加到self childViewControllers數組中保存 for (Column *column in _columns) { Class c = NSClassFromString(column.columnClassName); UIViewController *childVC =nil; if ([NSStringFromClass(c) isEqualToString:@"MoreViewController"]) { // 特別注意:在繼承了tableView之后,要想再使用group樣式,必須在創建的時候指定樣式為group,這兒特別指的是moreViewController childVC = [[c alloc]initWithStyle:UITableViewStyleGrouped]; } else { childVC = [[c alloc]init]; } // 設置導航欄的標題 childVC.navigationItem.title = column.columnName; // 重寫父類的方法 [self addChildViewController:childVC]; }}#pragma marck - 重寫父類的方法// 為了在添加子控制器時,全部包裝成一個個導航控制器,所以重寫addChildViewController方法- (void)addChildViewController:(UIViewController *)childVC{ UINavigationController *nav = [[UINavigationController alloc]initWithRootViewController:childVC]; // 將包裝成導航控制器的子控制器添加到主控制器中,這樣每一個子控制器就擁有自己的特有的導航條了 [super addChildViewController:nav];}// 4.一次性設置全局的導航欄上面的顏色主題樣式- (void)setGlobalNavigationItemColorTheme{ // 1.導航欄 // 1.1.操作navBar相當操作整個應用中的所有導航欄 UINavigationBar *navBar = [UINavigationBar appearance]; // 1.2.設置導航欄UINavigationBar的背景圖片(拉伸) [navBar setBackgroundImage:[UIImage imageStretchedWithName:@"navigationbar_background.png"] forBarMetrics:UIBarMetricsDefault]; // 1.3.設置狀態欄背景,沒有效果??? [UIApplication sharedApplication].statusBarStyle = UIStatusBarStyleLightContent; // 1.4.設置導航欄UINavigationBar的Title文字屬性,通過字典 設置 NSMutableDictionary *navigationBarTitleDict = [NSMutableDictionary dictionary]; // 前景色,即文字的顏色 [navigationBarTitleDict setObject:[UIColor darkGrayColor] forKey:NSForegroundColorAttributeName]; // 文字陰影取消,字典中不能放結構體,要用NSValue包裝一下 [navigationBarTitleDict setObject:[NSValue valueWithUIOffset:UIOffsetZero] forKey:NSShadowAttributeName]; // 2.導航欄上面的item UIBarButtonItem *barBtnItem =[UIBarButtonItem appearance]; // 2.1.設置背景 // 按鈕正常狀態時侯的背景 [barBtnItem setBackgroundImage:[UIImage imageNamed:@"navigationbar_button_background.png"] forState:UIControlStateNormal barMetrics:UIBarMetricsDefault]; // 按鈕高亮狀態時侯的背景 [barBtnItem setBackgroundImage:[UIImage imageNamed:@"navigationbar_button_background_pushed.png"] forState:UIControlStateHighlighted barMetrics:UIBarMetricsDefault]; // 按鈕未選中狀態時侯的背景 [barBtnItem setBackgroundImage:[UIImage imageNamed:@"navigationbar_button_background_disable.png"] forState:UIControlStateDisabled barMetrics:UIBarMetricsDefault]; // 2.2.設置barBtnItem的文字屬性 NSMutableDictionary *barItemTitleDict = [NSMutableDictionary dictionary]; // barItemDict的文字顏色 [barItemTitleDict setValue:[UIColor darkGrayColor] forKey:NSForegroundColorAttributeName]; // barItemDict的字體 [barItemTitleDict setValue:[UIFont systemFontOfSize:13] forKey:NSFontAttributeName]; // 2.3.用字典 設置barBtnItem的標題文字屬性 [barBtnItem setTitleTextAttributes:barItemTitleDict forState:UIControlStateNormal]; [barBtnItem setTitleTextAttributes:barItemTitleDict forState:UIControlStateHighlighted];}@end
Dock.h
//// Dock.h// 20_帥哥no微博//// Created by beyond on 14-8-3.// Copyright (c) 2014年 com.beyond. All rights reserved.// Dock就是主控制器下面的一條bar,它里面是由一個個按鈕DockBtn組成#import@class DockBtn;@interface Dock : UIView// 添加一個item到Dock(View),參數是圖標名,和要顯示 的標題 ,以及對應的子控制器的類名- (void)addDockBtnWithIconName:(NSString *)iconName title:(NSString *)title viewControllerClassName:(NSString *)viewControllerClassName;// 當Dock里面的某一個按鈕被點擊了的時候,調用代碼塊,處理相應的點擊事件@property (copy,nonatomic) void(^btnClickBlock)(DockBtn *);// 自定義方法,通過代碼決定哪一個dockBtn被點擊了,參數是 Dock欄里面的那個將要被點擊的按鈕的索引- (void)setDockBtnClickedAtIndex:(int)index;@end
Dock.m
//// Dock.m// 20_帥哥no微博//// Created by beyond on 14-8-3.// Copyright (c) 2014年 com.beyond. All rights reserved.// 這個就是主控制器下面那一欄,Tabbar,也叫Dock,里面有五個按鈕,分別是首頁,我,消息,廣場,更多#import "Dock.h"#import "DockBtn.h"@interface Dock(){ // 當前選中了那個dockBtn DockBtn *_currentDockBtn;}@end@implementation Dock// init方法內部會調用initWithFramne- (id)initWithFrame:(CGRect)frame{ self = [super initWithFrame:frame]; if (self) { // 固有固定屬性,設置Dock背景顏色(分類方法,使用imageName就可進行平鋪) self.backgroundColor = [UIColor colorWithPatternImageNamed:@"tabbar_background.png"]; } return self;}// 給外部提供一個接口,添加一個DockBtn(按鈕)到Dock(View),參數是圖標名,和要顯示 的標題,以及對應的子控制器的類名- (void)addDockBtnWithIconName:(NSString *)iconName title:(NSString *)title viewControllerClassName:(NSString *)viewControllerClassName{ // 1.創建dock里面的按鈕,并添加到dock里面 DockBtn *dockBtn = [DockBtn buttonWithType:UIButtonTypeCustom]; [self addSubview:dockBtn]; // 2.設置dockBtn正常狀態下顯示 的文字 [dockBtn setTitle:title forState:UIControlStateNormal]; // 3.分類方法,設置按鈕正常和選中狀態下的圖片,返回圖片尺寸 [dockBtn setBtnImgForNormalAndSelectedWithName:iconName]; // 4.設置dockBtn對應點擊后,要實例化的子控制器的類名 [dockBtn setViewControllerClassName:viewControllerClassName]; // 5.監聽點擊,只要按下就響應,(事件先傳遞給Dock的方法,Dock的方法中再通過調用屬性block代碼塊,從而調用到主控制器里面的代碼,原因是:在主控制器里面實例化的dock,在Dock里面才實例化的dockBtn,因此,主控制器并不知道dockItem的存在) [dockBtn addTarget:self action:@selector(dockBtnClick:) forControlEvents:UIControlEventTouchDown]; // 6.遍歷設置Dock里面所有按鈕的frame (使之平均分布) [self setDockBtnFrames];}// 遍歷設置Dock里面所有按鈕的frame (使之平均分布)- (void)setDockBtnFrames{ // 1,獲取dock里面所有的按鈕個數 int dockBtnNum = self.subviews.count; // 2,根據dock中,當前當前有多少個DockBtn,計算出每個dockBtn的寬度(self是dock,320*44) CGFloat dockBtnWidth = self.frame.size.width / dockBtnNum; CGFloat dockBtnHeight = self.frame.size.height; for (int i = 0; i = self.subviews.count) return; // 2.通過索引 拿到對應的DockBtn viewWithTag也行 DockBtn *btn = self.subviews[index]; // 3.手動調用下面方法,相當于用戶用手點擊了dock里面對應的按鈕 [self dockBtnClick:btn];}@end
DockBtn.h
//// DockBtn.h// 20_帥哥no微博//// Created by beyond on 14-8-4.// Copyright (c) 2014年 com.beyond. All rights reserved.// 一個DockBtn代表Dock上面的一個按鈕,它有個成員是對應子控制器的類名,比如Home按鈕,成員屬性的值就是叫:HomeViewController#import@interface DockBtn : UIButton// 每個dockBtn中,用一個成員記住 它對應的控制器的類名@property (nonatomic,copy) NSString *viewControllerClassName;@end
DockBtn.m
//// DockBtn.m// 20_帥哥no微博//// Created by beyond on 14-8-4.// Copyright (c) 2014年 com.beyond. All rights reserved.// 一個DockBtn代表Dock上面的一個按鈕,它有個成員是對應子控制器的類名,比如Home按鈕,成員屬性的值就是叫:HomeViewController#import "DockBtn.h"http:// 按鈕的內容的總寬度#define kBtnContentWidth contentRect.size.width// 按鈕的內容的總高度#define kBtnContentHeight contentRect.size.height// 按鈕里的圖片的所占的高度比例#define kImageHeightRatio 0.6// 按鈕里的文本標簽的所占的高度比例#define kLabelHeightRatio (1- kImageHeightRatio)@implementation DockBtn// 一些默認的通用的屬性一定要寫在構造方法里面- (id)initWithFrame:(CGRect)frame{ self = [super initWithFrame:frame]; if (self) { // 1.設置按鈕文字屬性 (局中,字體大小) self.titleLabel.textAlignment = NSTextAlignmentCenter; self.titleLabel.font = [UIFont systemFontOfSize:12]; // 2.設置按鈕圖片屬性 (放大模式,取消按鈕默認的點擊高亮時的變色) self.imageView.contentMode = UIViewContentModeScaleAspectFit; // 取消按鈕默認的點擊高亮時的變色(image is drawn darker when highlighted or pressed) self.adjustsImageWhenHighlighted = NO; // 3.分類方法,設置按鈕選中時的背景 [self setBgImgForSelected:@"tabbar_slider.png"]; } return self;}#pragma mark 重寫父類的方法(覆蓋父類在高亮時所作的行為)- (void)setHighlighted:(BOOL)highlighted{ // 因為 這里只需用按鈕的選中和默認狀態時的圖片,所以要取消高亮狀態的一些默認變色行為 // 這里什么也不寫,即取消,按鈕本身 在高亮的時候執行的那些行為 }#pragma mark 返回是按鈕內部UIImageView的邊框(按鈕中的圖片在上方,居中)- (CGRect)imageRectForContentRect:(CGRect)contentRect{ // 要居中,最快辦法就是讓按鈕中的圖片寬度和按鈕一樣寬 return CGRectMake(0, 0, kBtnContentWidth, kBtnContentHeight * kImageHeightRatio);}#pragma mark 返回是按鈕內部UILabel的邊框(按鈕中的文字在下方,居中)- (CGRect)titleRectForContentRect:(CGRect)contentRect{ // 要居中,最快辦法就是讓按鈕中的Label寬度和按鈕一樣寬 // 文字的y位于圖片的下邊線的上方5個單位距離,即距離圖片上方5 CGFloat labelY = kBtnContentHeight * kImageHeightRatio - 5; // 文字的高度是占按鈕余下的所有高度 CGFloat labelHeight = kBtnContentHeight - labelY; return CGRectMake(0, labelY, kBtnContentWidth, labelHeight);}@end
模型Column.h
//// Column.h// 20_帥哥no微博//// Created by beyond on 14-8-4.// Copyright (c) 2014年 com.beyond. All rights reserved.// 1個Column模型對應Dock上面的一個按鈕,類別#import// 數據模型 代表一個欄目@interface Column : NSObject// 欄目名稱@property (nonatomic,copy)NSString *columnName;// 欄目圖片名稱@property (nonatomic,copy)NSString *columnImgName;// 欄目對應的控制器的類名@property (nonatomic,copy)NSString *columnClassName;// UI控件用weak,字符串用copy,其他對象用strong// 提供一個類方法,即構造函數,返回封裝好數據的對象(返回id亦可)+ (Column *)columnNamed:(NSString *)columnName imgName:(NSString*)columnImgName className:(NSString *)columnClassName;// 類方法,字典 轉 對象 類似javaBean一次性填充+ (Column *)columnWithDict:(NSDictionary *)dict;// 對象方法,設置對象的屬性后,返回對象- (Column *)initWithDict:(NSDictionary *)dict;@end
模型Column.m
//// Column.m// 20_帥哥no微博//// Created by beyond on 14-8-4.// Copyright (c) 2014年 com.beyond. All rights reserved.//#import "Column.h"@implementation Column// 返回一個包含了 欄目對應控制器名字的 對象實例+ (Column *)columnNamed:(NSString *)columnName imgName:(NSString *)columnImgName className:(NSString *)columnClassName{ // 為了兼容子類 使用self Column *column = [[self alloc]init]; column.columnName = columnName; column.columnImgName = columnImgName; column.columnClassName = columnClassName; return column;}// 類方法,字典 轉 對象 類似javaBean一次性填充+ (Column *)columnWithDict:(NSDictionary *)dict{ // 只是調用對象的initWithDict方法,之所以用self是為了對子類進行兼容 return [[self alloc]initWithDict:dict];}// 對象方法,設置對象的屬性后,返回對象- (Column *)initWithDict:(NSDictionary *)dict{ // 必須先調用父類NSObject的init方法 if (self = [super init]) { // 設置對象自己的屬性 [self setValuesForKeysWithDictionary:dict]; } // 返回填充好的對象 return self;}@end
Dock里面的五個欄目按鈕的數據來源ColumnList.plist
新聞熱點
疑難解答