iOS開發(fā)之路--微博骨架搭建
更新時(shí)間:2014年08月26日 15:23:44 投稿:hebedich
本文是IOS開發(fā)之路的第四篇,主要講訴如何一步步搭建起微博的骨架,并附上源碼,希望對(duì)大家的IOS開發(fā)能提供些借鑒
最終效果圖:
BeyondViewController.m
// // BeyondViewController.m // 20_帥哥no微博 // // Created by beyond on 14-8-3. // Copyright (c) 2014年 com.beyond. All rights reserved. // 這個(gè)就是主控制器,分為兩塊,下面是Dock欄,上面是顯示不同的子控制器的view,子控制器最好用導(dǎo)航控制器包裝一下,這樣子控制器就自帶了導(dǎo)航條,左按鈕,標(biāo)題,右按鈕 /* 無法點(diǎn)擊,或點(diǎn)擊 無響應(yīng)的原因: userInteractionEnabled = NO; hidden = YES alpha <= 0.01 clearColor ,view的顏色為透明,不可以被點(diǎn)擊 */ #import "BeyondViewController.h" #import "Dock.h" #import "DockBtn.h" #import "Column.h" // 主控制器下面Dock的高度 #define kDockHeight 44 @interface BeyondViewController () { // 從plist中加載 的欄目對(duì)象數(shù)組 NSMutableArray *_columns; // 主控制器下方的Dock選項(xiàng)欄 Dock *_dock; // 記錄當(dāng)前選中的子控制器,目的是將其view從父控制器的view中移除,為添加新的子控制器的view做準(zhǔn)備 UIViewController *_currentChildVC; } @end @implementation BeyondViewController - (BOOL)prefersStatusBarHidden { return NO; } - (void)viewDidLoad { [super viewDidLoad]; // 0.從plist加載 欄目數(shù)組,遍歷數(shù)組,根據(jù)字典,生成一個(gè)一個(gè)欄目對(duì)象,存入欄目對(duì)象數(shù)組中 _columns = [NSMutableArray array]; NSBundle *mainBundle = [NSBundle mainBundle]; NSString *fullPath = [mainBundle pathForResource:@"ColumnList.plist" ofType:nil]; NSArray *arr = [NSArray arrayWithContentsOfFile:fullPath]; for (NSDictionary *dict in arr) { Column *column = [Column columnWithDict:dict]; [_columns addObject:column]; } // 1.添加dock到主控制器方的下方 [self addDock]; // 2.一次性創(chuàng)建所有的子控制器,并用導(dǎo)航包裝后,添加到當(dāng)前控制器的childViewControllers [self createAllChildViewControllers]; // 3.默認(rèn)選中第0個(gè)控制器 [self changeChildViewAtIndex:0 andChildVCClassName:@"HomeViewController"]; // 4.一次性設(shè)置全局的導(dǎo)航欄上面的顏色主題樣式 [self setGlobalNavigationItemColorTheme]; } #pragma mark 添加dock - (void)addDock { // 1.添加dock到主控制器方的下方 _dock = [[Dock alloc] init]; // 2.監(jiān)聽Dock內(nèi)部Btn的點(diǎn)擊,讓控制器成為dock的代理屬性,或者,為dock的成員blok賦值 __unsafe_unretained BeyondViewController *beyond = self; _dock.btnClickBlock = ^(DockBtn *btn) { // 調(diào)用自定義方法,更改子視圖,參數(shù)1:索引號(hào),參數(shù)2:子控制器的類名 [beyond changeChildViewAtIndex:btn.tag andChildVCClassName:btn.viewControllerClassName]; }; // 3,設(shè)置Dock的frame _dock.frame = CGRectMake(0, self.view.frame.size.height - kDockHeight, self.view.frame.size.width, kDockHeight); log(@"_dock frame--%@",NSStringFromCGRect(_dock.frame)); // 4,添加dock到主控制器方的view [self.view addSubview:_dock]; // 2.遍歷column對(duì)象數(shù)組,批量添加dock里面的DockBtn for (Column *column in _columns) { [_dock addDockBtnWithIconName:column.columnImgName title:column.columnName viewControllerClassName:column.columnClassName]; } // 3.設(shè)置dock默認(rèn)選中第0個(gè) [_dock setDockBtnClickedAtIndex:0]; } // 自定義方法,更改子視圖,參數(shù)1:索引號(hào),參數(shù)2:子控制器的類名 - (void)changeChildViewAtIndex:(int)index andChildVCClassName:(NSString *)viewControllerClassName { log(@"點(diǎn)擊了 %@",viewControllerClassName); if (self.childViewControllers.count > 0) { // 0,先取出新的子控制器,如果 新的子控制器就是當(dāng)前的這個(gè)控制器,直接返回 好嗎? 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)); // 不會(huì)重復(fù)添加view,因?yàn)橐坏┌l(fā)現(xiàn)重復(fù)添加某個(gè)view,就會(huì)將它置于最上面,最好是,先移除舊的view,再添加新的view [self.view addSubview:childVC.view ]; // 3,重要,必須更新當(dāng)前的子控制器,為下次移除做準(zhǔn)備 _currentChildVC = childVC; } } #pragma mark 創(chuàng)建所有的子控制器(一共5個(gè),首面,消息,我,廣場(chǎng),更多) - (void)createAllChildViewControllers { // 1.遍歷欄目對(duì)象數(shù)組,批量創(chuàng)建所有的子控制器,并用導(dǎo)航控制器包裝,最后添加到self childViewControllers數(shù)組中保存 for (Column *column in _columns) { Class c = NSClassFromString(column.columnClassName); UIViewController *childVC =nil; if ([NSStringFromClass(c) isEqualToString:@"MoreViewController"]) { // 特別注意:在繼承了tableView之后,要想再使用group樣式,必須在創(chuàng)建的時(shí)候指定樣式為group,這兒特別指的是moreViewController childVC = [[c alloc]initWithStyle:UITableViewStyleGrouped]; } else { childVC = [[c alloc]init]; } // 設(shè)置導(dǎo)航欄的標(biāo)題 childVC.navigationItem.title = column.columnName; // 重寫父類的方法 [self addChildViewController:childVC]; } } #pragma marck - 重寫父類的方法 // 為了在添加子控制器時(shí),全部包裝成一個(gè)個(gè)導(dǎo)航控制器,所以重寫addChildViewController方法 - (void)addChildViewController:(UIViewController *)childVC { UINavigationController *nav = [[UINavigationController alloc]initWithRootViewController:childVC]; // 將包裝成導(dǎo)航控制器的子控制器添加到主控制器中,這樣每一個(gè)子控制器就擁有自己的特有的導(dǎo)航條了 [super addChildViewController:nav]; } // 4.一次性設(shè)置全局的導(dǎo)航欄上面的顏色主題樣式 - (void)setGlobalNavigationItemColorTheme { // 1.導(dǎo)航欄 // 1.1.操作navBar相當(dāng)操作整個(gè)應(yīng)用中的所有導(dǎo)航欄 UINavigationBar *navBar = [UINavigationBar appearance]; // 1.2.設(shè)置導(dǎo)航欄UINavigationBar的背景圖片(拉伸) [navBar setBackgroundImage:[UIImage imageStretchedWithName:@"navigationbar_background.png"] forBarMetrics:UIBarMetricsDefault]; // 1.3.設(shè)置狀態(tài)欄背景,沒有效果??? [UIApplication sharedApplication].statusBarStyle = UIStatusBarStyleLightContent; // 1.4.設(shè)置導(dǎo)航欄UINavigationBar的Title文字屬性,通過字典 設(shè)置 NSMutableDictionary *navigationBarTitleDict = [NSMutableDictionary dictionary]; // 前景色,即文字的顏色 [navigationBarTitleDict setObject:[UIColor darkGrayColor] forKey:NSForegroundColorAttributeName]; // 文字陰影取消,字典中不能放結(jié)構(gòu)體,要用NSValue包裝一下 [navigationBarTitleDict setObject:[NSValue valueWithUIOffset:UIOffsetZero] forKey:NSShadowAttributeName]; // 2.導(dǎo)航欄上面的item UIBarButtonItem *barBtnItem =[UIBarButtonItem appearance]; // 2.1.設(shè)置背景 // 按鈕正常狀態(tài)時(shí)侯的背景 [barBtnItem setBackgroundImage:[UIImage imageNamed:@"navigationbar_button_background.png"] forState:UIControlStateNormal barMetrics:UIBarMetricsDefault]; // 按鈕高亮狀態(tài)時(shí)侯的背景 [barBtnItem setBackgroundImage:[UIImage imageNamed:@"navigationbar_button_background_pushed.png"] forState:UIControlStateHighlighted barMetrics:UIBarMetricsDefault]; // 按鈕未選中狀態(tài)時(shí)侯的背景 [barBtnItem setBackgroundImage:[UIImage imageNamed:@"navigationbar_button_background_disable.png"] forState:UIControlStateDisabled barMetrics:UIBarMetricsDefault]; // 2.2.設(shè)置barBtnItem的文字屬性 NSMutableDictionary *barItemTitleDict = [NSMutableDictionary dictionary]; // barItemDict的文字顏色 [barItemTitleDict setValue:[UIColor darkGrayColor] forKey:NSForegroundColorAttributeName]; // barItemDict的字體 [barItemTitleDict setValue:[UIFont systemFontOfSize:13] forKey:NSFontAttributeName]; // 2.3.用字典 設(shè)置barBtnItem的標(biāo)題文字屬性 [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,它里面是由一個(gè)個(gè)按鈕DockBtn組成 #import <UIKit/UIKit.h> @class DockBtn; @interface Dock : UIView // 添加一個(gè)item到Dock(View),參數(shù)是圖標(biāo)名,和要顯示 的標(biāo)題 ,以及對(duì)應(yīng)的子控制器的類名 - (void)addDockBtnWithIconName:(NSString *)iconName title:(NSString *)title viewControllerClassName:(NSString *)viewControllerClassName; // 當(dāng)Dock里面的某一個(gè)按鈕被點(diǎn)擊了的時(shí)候,調(diào)用代碼塊,處理相應(yīng)的點(diǎn)擊事件 @property (copy,nonatomic) void(^btnClickBlock)(DockBtn *); // 自定義方法,通過代碼決定哪一個(gè)dockBtn被點(diǎn)擊了,參數(shù)是 Dock欄里面的那個(gè)將要被點(diǎn)擊的按鈕的索引 - (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. // 這個(gè)就是主控制器下面那一欄,Tabbar,也叫Dock,里面有五個(gè)按鈕,分別是首頁,我,消息,廣場(chǎng),更多 #import "Dock.h" #import "DockBtn.h" @interface Dock() { // 當(dāng)前選中了那個(gè)dockBtn DockBtn *_currentDockBtn; } @end @implementation Dock // init方法內(nèi)部會(huì)調(diào)用initWithFramne - (id)initWithFrame:(CGRect)frame { self = [super initWithFrame:frame]; if (self) { // 固有固定屬性,設(shè)置Dock背景顏色(分類方法,使用imageName就可進(jìn)行平鋪) self.backgroundColor = [UIColor colorWithPatternImageNamed:@"tabbar_background.png"]; } return self; } // 給外部提供一個(gè)接口,添加一個(gè)DockBtn(按鈕)到Dock(View),參數(shù)是圖標(biāo)名,和要顯示 的標(biāo)題,以及對(duì)應(yīng)的子控制器的類名 - (void)addDockBtnWithIconName:(NSString *)iconName title:(NSString *)title viewControllerClassName:(NSString *)viewControllerClassName { // 1.創(chuàng)建dock里面的按鈕,并添加到dock里面 DockBtn *dockBtn = [DockBtn buttonWithType:UIButtonTypeCustom]; [self addSubview:dockBtn]; // 2.設(shè)置dockBtn正常狀態(tài)下顯示 的文字 [dockBtn setTitle:title forState:UIControlStateNormal]; // 3.分類方法,設(shè)置按鈕正常和選中狀態(tài)下的圖片,返回圖片尺寸 [dockBtn setBtnImgForNormalAndSelectedWithName:iconName]; // 4.設(shè)置dockBtn對(duì)應(yīng)點(diǎn)擊后,要實(shí)例化的子控制器的類名 [dockBtn setViewControllerClassName:viewControllerClassName]; // 5.監(jiān)聽點(diǎn)擊,只要按下就響應(yīng),(事件先傳遞給Dock的方法,Dock的方法中再通過調(diào)用屬性block代碼塊,從而調(diào)用到主控制器里面的代碼,原因是:在主控制器里面實(shí)例化的dock,在Dock里面才實(shí)例化的dockBtn,因此,主控制器并不知道dockItem的存在) [dockBtn addTarget:self action:@selector(dockBtnClick:) forControlEvents:UIControlEventTouchDown]; // 6.遍歷設(shè)置Dock里面所有按鈕的frame (使之平均分布) [self setDockBtnFrames]; } // 遍歷設(shè)置Dock里面所有按鈕的frame (使之平均分布) - (void)setDockBtnFrames { // 1,獲取dock里面所有的按鈕個(gè)數(shù) int dockBtnNum = self.subviews.count; // 2,根據(jù)dock中,當(dāng)前當(dāng)前有多少個(gè)DockBtn,計(jì)算出每個(gè)dockBtn的寬度(self是dock,320*44) CGFloat dockBtnWidth = self.frame.size.width / dockBtnNum; CGFloat dockBtnHeight = self.frame.size.height; for (int i = 0; i < dockBtnNum; i++) { // 1.逐個(gè)取出子控件 DockBtn *btn = self.subviews[i]; // 2.根據(jù)索引 計(jì)算它的x btn.frame = CGRectMake(i * dockBtnWidth, 0, dockBtnWidth, dockBtnHeight); // 3.初始化的時(shí)候,將第0個(gè)btn(即首頁)選中 if (i == 0) { btn.selected = YES; // 最重要的是,將選中的,置為當(dāng)前的按鈕,用成員變量記住,當(dāng)點(diǎn)擊dock上button的時(shí)候,先將current置為未選中,然后就被點(diǎn)擊的按鈕選中,最后最重要的是,將被點(diǎn)擊的按鈕重新置為當(dāng)前 的按鈕,用成員變量記住 _currentDockBtn = btn; } // 4.因?yàn)辄c(diǎn)擊dock里面的按鈕的時(shí)候,要知道點(diǎn)擊了哪一個(gè)按鈕,所以給每個(gè)按鈕綁定一個(gè)tag,作為它的索引 btn.tag = i; } } // 最重要的是,當(dāng)點(diǎn)擊dock上button的時(shí)候,先將current置為未選中,然后就被點(diǎn)擊的按鈕選中,最后最重要的是,將被點(diǎn)擊的按鈕重新置為當(dāng)前 的按鈕,用成員變量記住 - (void)dockBtnClick:(DockBtn *)btn { // 1.讓當(dāng)前的btn取消選中 _currentDockBtn.selected = NO; // 2.讓新的btn選中 btn.selected = YES; // 3.最后,讓新的btn變?yōu)楫?dāng)前選中btn _currentDockBtn = btn; // 4.調(diào)用block,即主控制中傳遞過來的代碼塊,目的是處理點(diǎn)擊之后的實(shí)例化對(duì)應(yīng)的子控制器 if (_btnClickBlock) { // 將參數(shù) DockBtn傳遞過去,給主控制器,它里面成員變量記住了它對(duì)應(yīng)的控制器的類名 _btnClickBlock(btn); } } // 自定義方法,通過代碼決定哪一個(gè)dockBtn被點(diǎn)擊了,參數(shù)是 Dock欄里面的那個(gè)將要被點(diǎn)擊的按鈕的索引 - (void)setDockBtnClickedAtIndex:(int)index { // 1.robust判斷 if (index < 0 || index >= self.subviews.count) return; // 2.通過索引 拿到對(duì)應(yīng)的DockBtn viewWithTag也行 DockBtn *btn = self.subviews[index]; // 3.手動(dòng)調(diào)用下面方法,相當(dāng)于用戶用手點(diǎn)擊了dock里面對(duì)應(yīng)的按鈕 [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. // 一個(gè)DockBtn代表Dock上面的一個(gè)按鈕,它有個(gè)成員是對(duì)應(yīng)子控制器的類名,比如Home按鈕,成員屬性的值就是叫:HomeViewController #import <UIKit/UIKit.h> @interface DockBtn : UIButton // 每個(gè)dockBtn中,用一個(gè)成員記住 它對(duì)應(yīng)的控制器的類名 @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. // 一個(gè)DockBtn代表Dock上面的一個(gè)按鈕,它有個(gè)成員是對(duì)應(yīng)子控制器的類名,比如Home按鈕,成員屬性的值就是叫:HomeViewController #import "DockBtn.h" // 按鈕的內(nèi)容的總寬度 #define kBtnContentWidth contentRect.size.width // 按鈕的內(nèi)容的總高度 #define kBtnContentHeight contentRect.size.height // 按鈕里的圖片的所占的高度比例 #define kImageHeightRatio 0.6 // 按鈕里的文本標(biāo)簽的所占的高度比例 #define kLabelHeightRatio (1- kImageHeightRatio) @implementation DockBtn // 一些默認(rèn)的通用的屬性一定要寫在構(gòu)造方法里面 - (id)initWithFrame:(CGRect)frame { self = [super initWithFrame:frame]; if (self) { // 1.設(shè)置按鈕文字屬性 (局中,字體大小) self.titleLabel.textAlignment = NSTextAlignmentCenter; self.titleLabel.font = [UIFont systemFontOfSize:12]; // 2.設(shè)置按鈕圖片屬性 (放大模式,取消按鈕默認(rèn)的點(diǎn)擊高亮?xí)r的變色) self.imageView.contentMode = UIViewContentModeScaleAspectFit; // 取消按鈕默認(rèn)的點(diǎn)擊高亮?xí)r的變色(image is drawn darker when highlighted or pressed) self.adjustsImageWhenHighlighted = NO; // 3.分類方法,設(shè)置按鈕選中時(shí)的背景 [self setBgImgForSelected:@"tabbar_slider.png"]; } return self; } #pragma mark 重寫父類的方法(覆蓋父類在高亮?xí)r所作的行為) - (void)setHighlighted:(BOOL)highlighted { // 因?yàn)?這里只需用按鈕的選中和默認(rèn)狀態(tài)時(shí)的圖片,所以要取消高亮狀態(tài)的一些默認(rèn)變色行為 // 這里什么也不寫,即取消,按鈕本身 在高亮的時(shí)候執(zhí)行的那些行為 } #pragma mark 返回是按鈕內(nèi)部UIImageView的邊框(按鈕中的圖片在上方,居中) - (CGRect)imageRectForContentRect:(CGRect)contentRect { // 要居中,最快辦法就是讓按鈕中的圖片寬度和按鈕一樣寬 return CGRectMake(0, 0, kBtnContentWidth, kBtnContentHeight * kImageHeightRatio); } #pragma mark 返回是按鈕內(nèi)部UILabel的邊框(按鈕中的文字在下方,居中) - (CGRect)titleRectForContentRect:(CGRect)contentRect { // 要居中,最快辦法就是讓按鈕中的Label寬度和按鈕一樣寬 // 文字的y位于圖片的下邊線的上方5個(gè)單位距離,即距離圖片上方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個(gè)Column模型對(duì)應(yīng)Dock上面的一個(gè)按鈕,類別 #import <Foundation/Foundation.h> // 數(shù)據(jù)模型 代表一個(gè)欄目 @interface Column : NSObject // 欄目名稱 @property (nonatomic,copy)NSString *columnName; // 欄目圖片名稱 @property (nonatomic,copy)NSString *columnImgName; // 欄目對(duì)應(yīng)的控制器的類名 @property (nonatomic,copy)NSString *columnClassName; // UI控件用weak,字符串用copy,其他對(duì)象用strong // 提供一個(gè)類方法,即構(gòu)造函數(shù),返回封裝好數(shù)據(jù)的對(duì)象(返回id亦可) + (Column *)columnNamed:(NSString *)columnName imgName:(NSString*)columnImgName className:(NSString *)columnClassName; // 類方法,字典 轉(zhuǎn) 對(duì)象 類似javaBean一次性填充 + (Column *)columnWithDict:(NSDictionary *)dict; // 對(duì)象方法,設(shè)置對(duì)象的屬性后,返回對(duì)象 - (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 // 返回一個(gè)包含了 欄目對(duì)應(yīng)控制器名字的 對(duì)象實(shí)例 + (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; } // 類方法,字典 轉(zhuǎn) 對(duì)象 類似javaBean一次性填充 + (Column *)columnWithDict:(NSDictionary *)dict { // 只是調(diào)用對(duì)象的initWithDict方法,之所以用self是為了對(duì)子類進(jìn)行兼容 return [[self alloc]initWithDict:dict]; } // 對(duì)象方法,設(shè)置對(duì)象的屬性后,返回對(duì)象 - (Column *)initWithDict:(NSDictionary *)dict { // 必須先調(diào)用父類NSObject的init方法 if (self = [super init]) { // 設(shè)置對(duì)象自己的屬性 [self setValuesForKeysWithDictionary:dict]; } // 返回填充好的對(duì)象 return self; } @end
Dock里面的五個(gè)欄目按鈕的數(shù)據(jù)來源ColumnList.plist
相關(guān)文章
iOS開發(fā)中常見的解析XML的類庫以及簡(jiǎn)要安裝方法
這篇文章主要介紹了iOS開發(fā)中常見的解析XML的類庫以及簡(jiǎn)要安裝方法,簡(jiǎn)要地說明了在Xcode下的一些特點(diǎn)以供對(duì)比,需要的朋友可以參考下2015-10-10IOS 長(zhǎng)鏈接與短鏈接之間的轉(zhuǎn)換
這篇文章主要介紹了IOS 長(zhǎng)鏈接與短鏈接之間的轉(zhuǎn)換的相關(guān)資料,需要的朋友可以參考下2017-06-06