iOS開發之路--微博骨架搭建_IOS

來源:互聯網
上載者:User

最終效果圖:


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.01 clearColor ,view的顏色為透明,不可以被點擊 */#import "BeyondViewController.h"#import "Dock.h"#import "DockBtn.h"#import "Column.h"// 主控制器下面Dock的高度#define kDockHeight 44@interface BeyondViewController (){  // 從plist中載入 的欄目對象數組  NSMutableArray *_columns;    // 主控制器下方的Dock選項欄  Dock *_dock;    // 記錄當前選中的子控制器,目的是將其view從父控制器的view中移除,為添加新的子控制器的view做準備  UIViewController *_currentChildVC;}@end@implementation BeyondViewController- (BOOL)prefersStatusBarHidden{  return NO;  }- (void)viewDidLoad{  [super viewDidLoad];  // 0.從plist載入 欄目數組,遍曆數組,根據字典,產生一個一個欄目對象,存入欄目對象數組中  _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.一次性建立所有的子控制器,並用導航封裝後,添加到當前控制器的childViewControllers  [self createAllChildViewControllers];    // 3.預設選中第0個控制器  [self changeChildViewAtIndex:0 andChildVCClassName:@"HomeViewController"];    // 4.一次性設定全域的導覽列上面的顏色主題樣式  [self setGlobalNavigationItemColorTheme];  }#pragma mark 添加dock- (void)addDock{  // 1.添加dock到主控制器方的下方  _dock = [[Dock alloc] init];    // 2.監聽Dock內部Btn的點擊,讓控制器成為dock的代理屬性,或者,為dock的成員blok賦值  __unsafe_unretained BeyondViewController *beyond = self;  _dock.btnClickBlock = ^(DockBtn *btn)  {    // 調用自訂方法,更改子視圖,參數1:索引號,參數2:子控制器的類名    [beyond changeChildViewAtIndex:btn.tag andChildVCClassName:btn.viewControllerClassName];  };      // 3,設定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對象數組,大量新增dock裡面的DockBtn  for (Column *column in _columns) {    [_dock addDockBtnWithIconName:column.columnImgName title:column.columnName viewControllerClassName:column.columnClassName];  }    // 3.設定dock預設選中第0個  [_dock setDockBtnClickedAtIndex:0];  }// 自訂方法,更改子視圖,參數1:索引號,參數2:子控制器的類名- (void)changeChildViewAtIndex:(int)index andChildVCClassName:(NSString *)viewControllerClassName{  log(@"點擊了 %@",viewControllerClassName);  if (self.childViewControllers.count > 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 <UIKit/UIKit.h>@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 < dockBtnNum; i++) {    // 1.逐個取出子控制項    DockBtn *btn = self.subviews[i];        // 2.根據索引 計算它的x    btn.frame = CGRectMake(i * dockBtnWidth, 0, dockBtnWidth, dockBtnHeight);        // 3.初始化的時候,將第0個btn(即首頁)選中    if (i == 0) {      btn.selected = YES;      // 最重要的是,將選中的,置為當前的按鈕,用成員變數記住,當點擊dock上button的時候,先將current置為未選中,然後就被點擊的按鈕選中,最後最重要的是,將被點擊的按鈕重新置為當前 的按鈕,用成員變數記住      _currentDockBtn = btn;    }        // 4.因為點擊dock裡面的按鈕的時候,要知道點擊了哪一個按鈕,所以給每個按鈕綁定一個tag,作為它的索引    btn.tag = i;  }}// 最重要的是,當點擊dock上button的時候,先將current置為未選中,然後就被點擊的按鈕選中,最後最重要的是,將被點擊的按鈕重新置為當前 的按鈕,用成員變數記住- (void)dockBtnClick:(DockBtn *)btn{  // 1.讓當前的btn取消選中  _currentDockBtn.selected = NO;    // 2.讓新的btn選中  btn.selected = YES;    // 3.最後,讓新的btn變為當前選中btn  _currentDockBtn = btn;    // 4.調用block,即主控制中傳遞過來的代碼塊,目的是處理點擊之後的執行個體化對應的子控制器  if (_btnClickBlock) {    // 將參數 DockBtn傳遞過去,給主控制器,它裡面成員變數記住了它對應的控制器的類名    _btnClickBlock(btn);  }}// 自訂方法,通過代碼決定哪一個dockBtn被點擊了,參數是 Dock欄裡面的那個將要被點擊的按鈕的索引- (void)setDockBtnClickedAtIndex:(int)index{  // 1.robust判斷  if (index < 0 || index >= 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 <UIKit/UIKit.h>@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"// 按鈕的內容的總寬度#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 <Foundation/Foundation.h>// 資料模型 代表一個欄目@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


相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.