最后效果图:

BeyondViewController.m

//
//  BeyondViewController.m
//  20_帅哥no微博
//
//  Created by beyond on 14-8-3.
//  Copyright (c) 2014年 com.beyond. All rights reserved.
//  这个就是主控制器,分为两块,以下是Dock栏,上面是显示不同的子控制器的view,子控制器最好用导航控制器包装一下,这样子控制器就自带了导航条,左button,标题,右button/*无法点击,或点击 无响应的原因:userInteractionEnabled = NO;hidden = YESalpha <= 0.01clearColor  ,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里面的DockBtnfor (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到主控制器的viewchildVC.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,这儿特别指的是moreViewControllerchildVC = [[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.导航栏上面的itemUIBarButtonItem *barBtnItem =[UIBarButtonItem appearance];// 2.1.设置背景// button正常状态时侯的背景[barBtnItem setBackgroundImage:[UIImage imageNamed:@"navigationbar_button_background.png"] forState:UIControlStateNormal barMetrics:UIBarMetricsDefault];// button高亮状态时侯的背景[barBtnItem setBackgroundImage:[UIImage imageNamed:@"navigationbar_button_background_pushed.png"] forState:UIControlStateHighlighted barMetrics:UIBarMetricsDefault];// button未选中状态时侯的背景[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,它里面是由一个个buttonDockBtn组成#import <UIKit/UIKit.h>
@class DockBtn;
@interface Dock : UIView
//  加入一个item到Dock(View),參数是图标名,和要显示 的标题 ,以及相应的子控制器的类名- (void)addDockBtnWithIconName:(NSString *)iconName title:(NSString *)title viewControllerClassName:(NSString *)viewControllerClassName;// 当Dock里面的某一个button被点击了的时候,调用代码块,处理相应的点击事件
@property (copy,nonatomic) void(^btnClickBlock)(DockBtn *);// 自己定义方法,通过代码决定哪一个dockBtn被点击了,參数是 Dock栏里面的那个将要被点击的button的索引
- (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,里面有五个button,各自是首页,我,消息,广场,很多其它#import "Dock.h"
#import "DockBtn.h"@interface Dock()
{// 当前选中了那个dockBtnDockBtn *_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(button)到Dock(View),參数是图标名,和要显示 的标题,以及相应的子控制器的类名
- (void)addDockBtnWithIconName:(NSString *)iconName title:(NSString *)title viewControllerClassName:(NSString *)viewControllerClassName
{// 1.创建dock里面的button,并加入到dock里面DockBtn *dockBtn = [DockBtn buttonWithType:UIButtonTypeCustom];[self addSubview:dockBtn];// 2.设置dockBtn正常状态下显示 的文字[dockBtn setTitle:title forState:UIControlStateNormal];// 3.分类方法,设置button正常和选中状态下的图片,返回图片尺寸[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里面全部button的frame (使之平均分布)[self setDockBtnFrames];
}// 遍历设置Dock里面全部button的frame (使之平均分布)
- (void)setDockBtnFrames
{// 1,获取dock里面全部的button个数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.依据索引 计算它的xbtn.frame = CGRectMake(i * dockBtnWidth, 0, dockBtnWidth, dockBtnHeight);// 3.初始化的时候,将第0个btn(即首页)选中if (i == 0) {btn.selected = YES;// 最重要的是,将选中的,置为当前的button,用成员变量记住,当点击dock上button的时候,先将current置为未选中,然后就被点击的button选中,最后最重要的是,将被点击的button又一次置为当前 的button,用成员变量记住_currentDockBtn = btn;}// 4.由于点击dock里面的button的时候,要知道点击了哪一个button,所以给每一个button绑定一个tag,作为它的索引btn.tag = i;}
}// 最重要的是,当点击dock上button的时候,先将current置为未选中,然后就被点击的button选中,最后最重要的是,将被点击的button又一次置为当前 的button,用成员变量记住
- (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栏里面的那个将要被点击的button的索引
- (void)setDockBtnClickedAtIndex:(int)index
{// 1.robust推断if (index < 0 || index >= self.subviews.count) return;// 2.通过索引 拿到相应的DockBtn  viewWithTag也行DockBtn *btn = self.subviews[index];// 3.手动调用以下方法,相当于用户用手点击了dock里面相应的button[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上面的一个button,它有个成员是相应子控制器的类名,比方Homebutton,成员属性的值就是叫: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上面的一个button,它有个成员是相应子控制器的类名,比方Homebutton,成员属性的值就是叫:HomeViewController#import "DockBtn.h"// button的内容的总宽度
#define kBtnContentWidth contentRect.size.width
// button的内容的总高度
#define kBtnContentHeight contentRect.size.height// button里的图片的所占的高度比例
#define kImageHeightRatio 0.6
// button里的文本标签的所占的高度比例
#define kLabelHeightRatio (1- kImageHeightRatio)@implementation DockBtn// 一些默认的通用的属性一定要写在构造方法里面
- (id)initWithFrame:(CGRect)frame
{self = [super initWithFrame:frame];if (self) {// 1.设置button文字属性 (局中,字体大小)self.titleLabel.textAlignment = NSTextAlignmentCenter;self.titleLabel.font = [UIFont systemFontOfSize:12];// 2.设置button图片属性 (放大模式,取消button默认的点击高亮时的变色)self.imageView.contentMode = UIViewContentModeScaleAspectFit;// 取消button默认的点击高亮时的变色(image is drawn darker when highlighted or pressed)self.adjustsImageWhenHighlighted = NO;// 3.分类方法,设置button选中时的背景[self setBgImgForSelected:@"tabbar_slider.png"];}return self;
}#pragma mark 重写父类的方法(覆盖父类在高亮时所作的行为)
- (void)setHighlighted:(BOOL)highlighted
{// 由于 这里仅仅需用button的选中和默认状态时的图片,所以要取消高亮状态的一些默认变色行为// 这里什么也不写,即取消,button本身 在高亮的时候运行的那些行为}#pragma mark 返回是button内部UIImageView的边框(button中的图片在上方,居中)
- (CGRect)imageRectForContentRect:(CGRect)contentRect
{// 要居中,最快办法就是让button中的图片宽度和button一样宽return CGRectMake(0, 0, kBtnContentWidth, kBtnContentHeight * kImageHeightRatio);
}#pragma mark 返回是button内部UILabel的边框(button中的文字在下方,居中)
- (CGRect)titleRectForContentRect:(CGRect)contentRect
{// 要居中,最快办法就是让button中的Label宽度和button一样宽// 文字的y位于图片的下边线的上方5个单位距离,即距离图片上方5CGFloat labelY = kBtnContentHeight * kImageHeightRatio - 5;// 文字的高度是占button余下的全部高度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上面的一个button,类别#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
{// 为了兼容子类 使用selfColumn *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里面的五个栏目button的数据来源ColumnList.plist

版权声明:本文博主原创文章。博客,未经同意不得转载。

iOS_20_微博的骨架结构相关推荐

  1. iOS_20_微博自己定义可动画切换的导航控制器

    终于效果: AnimatedNavigationController.h // // AnimatedNavigationController.h // 20_帅哥no微博 // // Created ...

  2. 小程序picker_小程序·云开发实战 - 迷你微博

    0. 前言 本文将手把手教你如何写出迷你版微博的一行行代码,迷你版微博包含以下功能: Feed 流:关注动态.所有动态 发送图文动态 搜索用户 关注系统 点赞动态 个人主页 使用到的云开发能力: 云数 ...

  3. android微博客户端下载,iBeebo微博客户端

    iBeebo微博客户端是一款免费的开源微博客户端,比起官方的手机客户端这款应用显然要小巧的多,它没有那些多余的无用功能.iBeebo微博客户端支持私信,你还可以查看热门话题和热门微博,喜欢的朋友不要错 ...

  4. 04.微博消息的语言检测

    04.微博消息的语言检测 郑昀 201010 隶属于<02.数据解析>小节 大意是,封装Google语言检测ajax web service的接口,输入一段话,输出语言种类.这个方法是从R ...

  5. 推荐本人微博及浅谈发博原则

    本人新浪微博:http://weibo.com/jinbinforever 花了一些力气,将关注数降到100以下,以后原则上关注数不会增加了.发现这样做的好处非常明显,减少了很多无谓的信息干扰.les ...

  6. 关于微博溯源的后续问题

    1.在进行关键词搜索的时候,如何分词,我们不可能用语料库进行匹配,已没有语料可以学习. 2.关于转折点的寻找.目前我们使用高级搜索,从当前时间往前推,根据搜索到微博的条数变化,确定时间发生具体时间(天 ...

  7. 腾讯微博API时间线相关接口返回的微博信息中head值使用问题

    腾讯微博API时间线相关接口返回的微博信息中head值表示作者头像url,这个链接直接访问并不能使用,需要再附加一个参数指定图片的大小(100.50),比如:[head]/100.

  8. 微博polg什么意思_贾磊:广东发微博给CBA造成了负面影响 方硕的意思可能没表达清楚...

    直播吧11月5日讯 近日做客一档节目时,著名篮球记者贾磊谈到了前天晚上的京粤大战. 贾磊谈到了王骁辉伸腿绊倒威姆斯一事:"我觉得这场比赛,王骁辉的这个动作,大家都看的非常清楚,确实是一个犯规 ...

  9. 腾讯微博快速有效增加广播转播量的方法与技巧

    经过一段时间对腾讯微博的实践,对腾讯微博也算是有所收获,要做好腾讯微博,无非就是两个方面,一是增加听众数,二是增加广播的转播量,本篇写的是做好微博质量–即增加转播量的方法. 增加转播量不像增加听众数那 ...

最新文章

  1. pta 插入排序还是堆排序
  2. html编写程序常用的,html编写简洁页面表单验证程序.doc
  3. 763. Partition Labels 划分字母区间
  4. MongoDB的集群模式--Replica Set
  5. 微信号承载私域流量的9条心得
  6. 全国主要省份城市的DNS服务器地址
  7. apply家活跃成员小聚会
  8. Python:身份运算符is和==的区别
  9. 转载的发现对自己非常有用,来分享给大家
  10. 慕课课程《简明世界史》课堂笔记二
  11. 美团的2020年:千亿美元帝国的贪吃蛇游戏,气势汹汹也危机重重
  12. c语言中 x20是什么意思,转义字符的问题,\ x00- \ x20是什么意思
  13. coreldraw高级快捷键技巧
  14. 基于PHP的班级分数量化管理系统
  15. 线性代数代码实现(五)求矩阵的逆(C++)
  16. FFmpeg —— 录制Windows桌面与麦克风,音视频同步(附源码)
  17. 0x80073712_win10系统更新提示错误代码“0x80073712”的解决方法
  18. 1089 质因数分解
  19. mac在终端打开mysql_如何在Mac上打开终端
  20. ecg信号越界_精确心电图ECG信号处理介绍

热门文章

  1. 添加七牛云存储_七牛云存储如何正确设置流量带宽告警配置(阈值告警)?
  2. Java web 圈子设计_关于Java web开发中的面向对象问题?
  3. jQuery的getter和setter
  4. linux内核模块开发(笔记),Linux内核模块学习笔记
  5. 1342.将数字变成0的操作次数
  6. php删除图片按钮代码,jquery 按钮预览图片功能的代码,我看不太懂。应该怎么学...
  7. php 处理像素点数组,求助:php处理这个数组
  8. 关于php正则表达式得选择题,经典PHP笔试题
  9. java io读取文件_java io读取文件操作代码实例
  10. 20200501:力扣185周赛上