一 整体布局:
if(未授权){
加载授权WabView(保存授权信息到本地沙盒) —>授权完成显示主页
//沙盒路径
NSString *doc = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES)lastObject];
NSString *path = [doc stringByAppendingPathComponent:@"account.archive"];
// NSLog(@"%@",path);
//将返回的账号数据 --> 模型再存到沙盒
MCAccountModel *account = [MCAccountModelaccountWithDic:responseObject];
//要想把对象写进沙盒就要用到 NSKeyedArchiver 这个类不能在使用writeToFile的方法
[NSKeyedArchiverarchiveRootObject:account toFile:path];
// [responseObject writeToFile:path atomically:YES];
}else{
if(根据沙盒路径下保存的新版本信息判断是否是新版本){
NSString *key = @"CFBundleVersion";
//1.获取上一次的软件版本(沙盒中)
//1.获取上一次的软件版本(沙盒中)
NSString *lastVersion = [[NSUserDefaultsstandardUserDefaults] objectForKey:key];
//2.获取当前版本(info.plist文件中)
NSString *currentVersion = [NSBundlemainBundle].infoDictionary[key];
UIWindow *window = [UIApplicationsharedApplication].keyWindow ;
if ([currentVersion isEqualToString:lastVersion]) {
window.rootViewController = tabBar;
}else{
window.rootViewController = [[NewFeatureViewControlleralloc]init];
//3.将新版本号存入沙盒
[[NSUserDefaultsstandardUserDefaults] setObject:currentVersion forKey:key];
[[NSUserDefaultsstandardUserDefaults]synchronize];
//3.将新版本号存入沙盒
[[NSUserDefaultsstandardUserDefaults] setObject:currentVersion forKey:key];
[[NSUserDefaultsstandardUserDefaults]synchronize];
}
显示“新特性界面”(更新沙盒路径下保存的新版本)—>主页
}else{
直接显示主页
}
}
在这里,保存到沙盒路径下的模型类需要说明一下,涉及到对象的归档和解档
#import
"MCAccountModel.h"
@implementation
MCAccountModel
+(instancetype)accountWithDic:(NSDictionary *)dic{
MCAccountModel *account = [[selfalloc]init];
account.access_token = [dic objectForKey:@"access_token"];
account.expires_in = [dic objectForKey:@"expires_in"];
account.uid = [dic objectForKey:@"uid"];
return
account;
}
/**
* 当一个对象要归档到沙盒中时要调用到这个方法 *
* 目的 : 在这个方法中说明对象的那些属性要存进沙盒
*/
}
/**
* 当一个对象要归档到沙盒中时要调用到这个方法 *
* 目的 : 在这个方法中说明对象的那些属性要存进沙盒
*/
-(void)encodeWithCoder:(NSCoder *)encoder{
[encoder
encodeObject
:
self
.
access_token
forKey:@"access_token"];
[encoder encodeObject:self.expires_inforKey:@"expires_in"];
[encoder encodeObject:self.expires_inforKey:@"expires_in"];
[encoder encodeObject:self.uidforKey:@"uid"];
}
/**
* 当一个对象要从沙盒中解档时要调用到这个方法
* 目的 : 在这个方法中说明对象的那些属性要从沙盒中解档
*/
/**
* 当一个对象要从沙盒中解档时要调用到这个方法
* 目的 : 在这个方法中说明对象的那些属性要从沙盒中解档
*/
-(instancetype)initWithCoder:(NSCoder *)decoder{
if
(
self
= [
super
init]) {
self.access_token = [decoder decodeObjectForKey:@"access_token"];
self.expires_in = [decoder decodeObjectForKey:@"expires_in"];
self.access_token = [decoder decodeObjectForKey:@"access_token"];
self.expires_in = [decoder decodeObjectForKey:@"expires_in"];
self.uid = [decoder decodeObjectForKey:@"uid"];
}
return self;
}
return self;
}
@end
二 主框架 :
主要的框架结构是 : 一个标签控制器下四个由导航控制器控制的ViewController,这里方法是将标签控制器子类化
MCBaseTabBarController
- (
void
)viewDidLoad {
[ super viewDidLoad];
//初始化子控制器
// 1.初始化子控制器
HomeViewController *home = [[HomeViewControlleralloc] init];
[ super viewDidLoad];
//初始化子控制器
// 1.初始化子控制器
HomeViewController *home = [[HomeViewControlleralloc] init];
[selfaddChildVc:home title:@"首页"image:@"tabbar_home"selectedImage:@"tabbar_home_selected"];
MassageViewController
*messageCenter = [[
MassageViewController
alloc] init];
[selfaddChildVc:messageCenter title:@"消息"image:@"tabbar_message_center"selectedImage:@"tabbar_message_center_selected"];
DiscoverViewController
*discover = [[
DiscoverViewController
alloc] init];
[selfaddChildVc:discover title:@"发现"image:@"tabbar_discover"selectedImage:@"tabbar_discover_selected"];
MyinfoViewController
*profile = [[
MyinfoViewController
alloc] init];
[selfaddChildVc:profile title:@"我"image:@"tabbar_profile"selectedImage:@"tabbar_profile_selected"];
MCTabBar
*tabBar = [[
MCTabBar
alloc]init];
tabBar.
delegate
=
self
;
// 系统只读模式的属性 我们可以用KVC赋值
[selfsetValue:tabBar forKeyPath:@"tabBar"];
// 系统只读模式的属性 我们可以用KVC赋值
[selfsetValue:tabBar forKeyPath:@"tabBar"];
}
-(
void
)viewWillAppear:(
BOOL
)animated{
[
super
viewWillAppear:animated];
}
- ( void )addChildVc:( UIViewController *)childVc title:( NSString *)title image:( NSString *)image selectedImage:( NSString *)selectedImage
{
// 设置子控制器的文字
- ( void )addChildVc:( UIViewController *)childVc title:( NSString *)title image:( NSString *)image selectedImage:( NSString *)selectedImage
{
// 设置子控制器的文字
childVc.title = title; //
同时设置
tabbar
和
navigationBar
的文字
//
设置子控制器的图片
childVc. tabBarItem . image = [ UIImage imageNamed:image];
childVc. tabBarItem . image = [ UIImage imageNamed:image];
childVc.tabBarItem.selectedImage = [[UIImageimageNamed:selectedImage]imageWithRenderingMode:UIImageRenderingModeAlwaysOriginal];
//
设置文字的样式
NSMutableDictionary *textAttrs = [ NSMutableDictionary dictionary];
textAttrs[NSForegroundColorAttributeName] = MCColor(123, 123, 123);
NSMutableDictionary *selectTextAttrs = [NSMutableDictionarydictionary];
selectTextAttrs[NSForegroundColorAttributeName] = [UIColororangeColor];
[childVc.tabBarItemsetTitleTextAttributes:textAttrs forState:UIControlStateNormal];
NSMutableDictionary *textAttrs = [ NSMutableDictionary dictionary];
textAttrs[NSForegroundColorAttributeName] = MCColor(123, 123, 123);
NSMutableDictionary *selectTextAttrs = [NSMutableDictionarydictionary];
selectTextAttrs[NSForegroundColorAttributeName] = [UIColororangeColor];
[childVc.tabBarItemsetTitleTextAttributes:textAttrs forState:UIControlStateNormal];
[childVc.tabBarItemsetTitleTextAttributes:selectTextAttrs forState:UIControlStateSelected];
//
先给外面传进来的小控制器
包装一个导航控制器
MCBaseNavigationController *nav = [[MCBaseNavigationControlleralloc] initWithRootViewController:childVc];
// 添加为子控制器
[selfaddChildViewController:nav];
MCBaseNavigationController *nav = [[MCBaseNavigationControlleralloc] initWithRootViewController:childVc];
// 添加为子控制器
[selfaddChildViewController:nav];
}
在上面过程中标签控制器的tabBar 是根据需求自定义的样式
- (
instancetype
)initWithFrame:(
CGRect
)frame
{
self = [ super initWithFrame:frame];
{
self = [ super initWithFrame:frame];
if (self) {
UIButton
*plusBtn = [[
UIButton
alloc]init];
[plusBtn
addTarget
:
self
action:@selector(plusBtnClick:) forControlEvents:UIControlEventTouchUpInside];
[plusBtn
setBackgroundImage
:[
UIImage
imageNamed:@"tabbar_compose_button"] forState:UIControlStateNormal];
[plusBtn setBackgroundImage:[UIImageimageNamed:@"tabbar_compose_button_highlighted"] forState:UIControlStateHighlighted];
[plusBtn setImage:[UIImageimageNamed:@"tabbar_compose_icon_add"] forState:UIControlStateNormal];
[plusBtn setBackgroundImage:[UIImageimageNamed:@"tabbar_compose_button_highlighted"] forState:UIControlStateHighlighted];
[plusBtn setImage:[UIImageimageNamed:@"tabbar_compose_icon_add"] forState:UIControlStateNormal];
[plusBtn setImage:[UIImageimageNamed:@"tabbar_compose_icon_add_highlighted"] forState:UIControlStateHighlighted];
plusBtn.
size
= plusBtn.
currentBackgroundImage
.
size
;
self
.
plusBtn
= plusBtn;
[
self
addSubview:plusBtn];
}
returnself;
}
returnself;
}
通常需要重新布局系统控件时,都要复写这个方法来给系统的控件重新布局
-(void)layoutSubviews{
[
super
layoutSubviews];
//1.
设置加号按钮的尺寸
self . plusBtn . centerX = self . width * 0.5 ;
self . plusBtn . centerX = self . width * 0.5 ;
self.plusBtn.centerY = self.height * 0.5;
//2.
设置其他控件的尺寸
CGFloat tabBarItemWith = self . width / 5 ;
int index = 0 ;
CGFloat tabBarItemWith = self . width / 5 ;
int index = 0 ;
for (UIView *view inself.subviews) {
Class class =
NSClassFromString
(
@"UITabBarButton"
);
if
([view
isKindOfClass
:class]) {
view. width = tabBarItemWith;
view. x = tabBarItemWith * index;
view. width = tabBarItemWith;
view. x = tabBarItemWith * index;
index ++;
if
(index ==
2
) {
index ++;
}
}
}
index ++;
}
}
}
}
三 模块共同属性和特点统一设置
通常同一款应用不同的界面会有相似的属性,我们把这些属性统一设置在一个父类当中,也就是子类化一个公共的父类,这样就会减少很多代码量
比如:每个模块的导航栏左右两个按钮都是相同的,并且每个模块中pushi出来的视图的导航栏中的按钮也是相同的,并且每个模块pushi出来的VIewController的标签栏都是隐藏的,总结出这些共同属性接下来就着手在父类中去实现这些属性就可以了,当用到这些属性时只需要基于这个父类 (
MCBaseNavigationController)创建类就可以了
UIBarButtonItem 在创建时(不管以什么方式创建)都会实现这个类方法,所以复写这个类方法,并添加共有属性
+ (
void
)initialize
{
// 设置整个项目中的 item 主题样式
{
// 设置整个项目中的 item 主题样式
UIBarButtonItem *item = [UIBarButtonItemappearance];
//
设置普通状态
// key : NS****AttributeName
// key : NS****AttributeName
NSMutableDictionary *textAttrs = [NSMutableDictionarydictionary];
textAttrs[
NSForegroundColorAttributeName
] = [
UIColor
orangeColor];
textAttrs[
NSFontAttributeName
] = [
UIFont
systemFontOfSize:13];
[item
setTitleTextAttributes
:textAttrs
forState
:
UIControlStateNormal
];
//
设置不可用状态
NSMutableDictionary *disableTextAttrs = [NSMutableDictionarydictionary];
disableTextAttrs[
NSForegroundColorAttributeName
] = [
UIColor
colorWithRed:0.6green:0.6blue:0.6alpha:0.7];
disableTextAttrs[
NSFontAttributeName
] = [
UIFont
systemFontOfSize:13];
[item
setTitleTextAttributes
:disableTextAttrs
forState
:
UIControlStateDisabled
];
}
/**
* * 重写这个方法的目的 : 能够拦截所有 Push 进来的控制器
* @param viewController 即将 push 进来的控制器
*/
/**
* * 重写这个方法的目的 : 能够拦截所有 Push 进来的控制器
* @param viewController 即将 push 进来的控制器
*/
-(void)pushViewController:(UIViewController *)viewController animated:(BOOL)animated{
if
(
self
.
viewControllers
.
count
>
0
) {
//
这时
pushi
进来的控制器
viewController,
不是第一个自控制器
(
不是跟控制器
)
/* 自动显示和隐藏 tabbar */
/* 自动显示和隐藏 tabbar */
viewController.hidesBottomBarWhenPushed = YES;
/*
设置导航栏上面的内容
*/
//
设置左侧按钮
viewController.navigationItem.leftBarButtonItem = [UIBarButtonItemitemWithTarget:selfaction:@selector(back) image:@"navigationbar_back"highImage:@"navigationbar_back_highlighted"];
//
设置右侧按钮
viewController. navigationItem . rightBarButtonItem = [ UIBarButtonItem itemWithTarget:selfaction:@selector(more) image:@"navigationbar_more"highImage:@"navigationbar_more_highlighted"];
}
viewController. navigationItem . rightBarButtonItem = [ UIBarButtonItem itemWithTarget:selfaction:@selector(more) image:@"navigationbar_more"highImage:@"navigationbar_more_highlighted"];
}
[superpushViewController:viewController animated:animated];
}
-(void)back{
[
self
popViewControllerAnimated:YES];
}
-(void)more{
[
self
popToRootViewControllerAnimated:YES];
}
四 控件的封装
项目中某些模块的控件需要实现复杂的功能,并且整个项目中有多个模块用到该控件,那么就要实现控件的封装,比如:首页(Home)的标题点击实现下拉菜单的功能,上述tabBar的封装,发现(Search)的搜索框都可以单独封装使用。
下拉菜单
#import
"MCTitleMenuView.h"
@interface MCTitleMenuView ()
{
UIImageView *_menuView;
}
@interface MCTitleMenuView ()
{
UIImageView *_menuView;
}
@end
@implementation
MCTitleMenuView
+(
instancetype
)menu{
return
[[
self
alloc]init];
}
-(void)showSelf:(UIButton*)btn{
//1.
获取最上面的窗口
UIWindow *window = [[UIApplicationsharedApplication].windowslastObject];
//2.
添加自己到窗口
[window addSubview:self];
//3.
设置尺寸
self.frame = window.bounds;
self
.
backgroundColor
= [
UIColor
clearColor];
self
.
userInteractionEnabled
=
YES
;
_menuView
= [[
UIImageView
alloc]initWithFrame:CGRectMake(20, 80, 200, 300)];
//
调节下拉菜单的位置
CGRect newRect = [btn convertRect :btn. bounds toView:nil];
CGRect newRect = [btn convertRect :btn. bounds toView:nil];
_menuView.centerX = btn.centerX;
_menuView
.
y
= newRect.
origin
.
y
+ btn.
height
;
_menuView.userInteractionEnabled = YES;
if
(
_content
) {
self . content . frame = CGRectMake ( 15 , 25 , _menuView . width - 30 , _menuView . height - 40 );
self . content . frame = CGRectMake ( 15 , 25 , _menuView . width - 30 , _menuView . height - 40 );
_content.layer.cornerRadius = 5;
[
_menuView
addSubview:_content];
}
}
_menuView
.
image
= [
UIImage
imageNamed:@"popover_background"];
[
self
addSubview:_menuView];
}
-(
void
)dismis{
[
_menuView
removeFromSuperview];
[
self
removeFromSuperview];
}
-( void )setContent:( UIView *)content{
_content = content;
}
-( void )setContent:( UIView *)content{
_content = content;
}
-(void)setShowButton:(UIButton *)showButton{
_showButton
= showButton;
}
}
-(void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event{
for
(
UITouch
*touch
in
touches) {
if
(
_content
) {
if (touch.view != _content) {
_showButton
.
selected
=
NO
;
[ self dismis];
}
}else{
if (touch.view != _menuView) {
[ self dismis];
}
}else{
if (touch.view != _menuView) {
_showButton.selected = NO;
[
self
dismis];
}
}
}
}
}
搜索框
#import
"MCSearchTextField.h"
@implementation MCSearchTextField
- ( instancetype )initWithFrame:( CGRect )frame
{
self = [ super initWithFrame:frame];
if (self) {
[selfcreatSearchTextfield];
}
returnself;
}
@implementation MCSearchTextField
- ( instancetype )initWithFrame:( CGRect )frame
{
self = [ super initWithFrame:frame];
if (self) {
[selfcreatSearchTextfield];
}
returnself;
}
-(void)creatSearchTextfield{
self
.
background
= [
UIImage
imageNamed:@"searchbar_textfield_background"];
self.backgroundColor = [UIColorwhiteColor];
self.placeholder = @"搜索内容";
self.layer.cornerRadius = 5;
self.layer.borderWidth = 1;
self.layer.borderColor = [UIColorlightGrayColor].CGColor;
UIImageView *imageView= [[UIImageViewalloc]initWithImage:[UIImageimageNamed:@"searchbar_textfield_search_icon"]];
imageView.width = 30;
imageView.height = 30;
self.backgroundColor = [UIColorwhiteColor];
self.placeholder = @"搜索内容";
self.layer.cornerRadius = 5;
self.layer.borderWidth = 1;
self.layer.borderColor = [UIColorlightGrayColor].CGColor;
UIImageView *imageView= [[UIImageViewalloc]initWithImage:[UIImageimageNamed:@"searchbar_textfield_search_icon"]];
imageView.width = 30;
imageView.height = 30;
imageView.contentMode = UIViewContentModeCenter;
self
.
leftView
= imageView;
self.leftViewMode = UITextFieldViewModeAlways;
}
@end