一:主框架分析:

1:主框架的效果图如下:底部有一个tabBar,点击tabBar按钮切换首页,信息,发现 和我几个界面。则考虑将UITabBarController作为窗口的根视图控制器,所以新建类继承UITabBarController,用来封装主框架


微博消息系统架构演进 微博信息框架_自定义

2:封装根视图控制器UITabBarController的代码:

1 #import "HMTabBarViewController.h"
  2 #import "HMHomeViewController.h"
  3 #import "HMMessageViewController.h"
  4 #import "HMDiscoverViewController.h"
  5 #import "HMProfileViewController.h"
  6 #import "HMNavigationController.h"
  7 #import "HMTabBar.h"
  8 #import "HMComposeViewController.h"
  9 #import "HMUserTool.h"
 10 #import "HMAccount.h"
 11 #import "HMAccountTool.h"
 12 
 13 @interface HMTabBarViewController () <HMTabBarDelegate, UITabBarControllerDelegate>
 14 @property (nonatomic, weak) HMHomeViewController *home;
 15 @property (nonatomic, weak) HMMessageViewController *message;
 16 @property (nonatomic, weak) HMProfileViewController *profile;
 17 @property (nonatomic, weak) UIViewController *lastSelectedViewContoller;
 18 @end
 19 
 20 @implementation HMTabBarViewController
 21 - (void)viewDidLoad
 22 {
 23     [super viewDidLoad];
 24     
 25     //1:自己设为自己的代理,为了监听自身的改变
 26      self.delegate = self;
 27     
 28     //2:添加所有的子控制器
 29     [self addAllChildVcs];
 30     
 31     //3:创建自定义tabbar
 32     [self addCustomTabBar];
 33     
 34     //4:利用定时器获得用户的未读数
 35 //    NSTimer *timer = [NSTimer scheduledTimerWithTimeInterval:10 target:self selector:@selector(getUnreadCount) userInfo:nil repeats:YES];
 36 //    [[NSRunLoop mainRunLoop] addTimer:timer forMode:NSRunLoopCommonModes];
 37 }
 38 
 39 #pragma mark -- 当切换控制器时,监听自身切换控制器
 40 
 41 - (void)tabBarController:(UITabBarController *)tabBarController didSelectViewController:(UINavigationController *)viewController
 42 {
 43     UIViewController *vc = [viewController.viewControllers firstObject];
 44     if ([vc isKindOfClass:[HMHomeViewController class]]) {
 45         if (self.lastSelectedViewContoller == vc) {
 46             [self.home refresh:YES];
 47         } else {
 48             [self.home refresh:NO];
 49         }
 50     }
 51     
 52     self.lastSelectedViewContoller = vc;
 53 }
 54 
 55 #pragma mark -- 获得未读数
 56 
 57 - (void)getUnreadCount
 58 {
 59     // 1.请求参数
 60     HMUnreadCountParam *param = [HMUnreadCountParam param];
 61     param.uid = [HMAccountTool account].uid;
 62     
 63     // 2.获得未读数
 64     [HMUserTool unreadCountWithParam:param success:^(HMUnreadCountResult *result) {
 65         // 显示微博未读数
 66         if (result.status == 0) {
 67             self.home.tabBarItem.badgeValue = nil;
 68         } else {
 69             self.home.tabBarItem.badgeValue = [NSString stringWithFormat:@"%d", result.status];
 70         }
 71         
 72         // 显示消息未读数
 73         if (result.messageCount == 0) {
 74             self.message.tabBarItem.badgeValue = nil;
 75         } else {
 76             self.message.tabBarItem.badgeValue = [NSString stringWithFormat:@"%d", result.messageCount];
 77         }
 78         
 79         // 显示新粉丝数
 80         if (result.follower == 0) {
 81             self.profile.tabBarItem.badgeValue = nil;
 82         } else {
 83             self.profile.tabBarItem.badgeValue = [NSString stringWithFormat:@"%d", result.follower];
 84         }
 85         
 86         // 在图标上显示所有的未读数
 87         [UIApplication sharedApplication].applicationIconBadgeNumber = result.totalCount;
 88         HMLog(@"总未读数--%d", result.totalCount);
 89     } failure:^(NSError *error) {
 90         HMLog(@"获得未读数失败---%@", error);
 91     }];
 92 }
 93 
 94 /**
 95  *  创建自定义tabbar
 96  */
 97 - (void)addCustomTabBar
 98 {
 99     // 创建自定义tabbar
100     HMTabBar *customTabBar = [[HMTabBar alloc] init];
101     customTabBar.tabBarDelegate = self;
102     // 更换系统自带的tabbar
103     [self setValue:customTabBar forKeyPath:@"tabBar"];
104 }
105 
106 /**
107  *  添加所有的子控制器
108  */
109 - (void)addAllChildVcs
110 {
111     HMHomeViewController *home = [[HMHomeViewController alloc] init];
112     [self addOneChlildVc:home title:@"首页" imageName:@"tabbar_home" selectedImageName:@"tabbar_home_selected"];
113     self.home = home;
114     self.lastSelectedViewContoller = home;
115     
116     HMMessageViewController *message = [[HMMessageViewController alloc] init];
117     [self addOneChlildVc:message title:@"消息" imageName:@"tabbar_message_center" selectedImageName:@"tabbar_message_center_selected"];
118     self.message = message;
119     
120     HMDiscoverViewController *discover = [[HMDiscoverViewController alloc] init];
121     [self addOneChlildVc:discover title:@"发现" imageName:@"tabbar_discover" selectedImageName:@"tabbar_discover_selected"];
122     
123     HMProfileViewController *profile = [[HMProfileViewController alloc] init];
124     [self addOneChlildVc:profile title:@"我" imageName:@"tabbar_profile" selectedImageName:@"tabbar_profile_selected"];
125     self.profile = profile;
126 }
127 
128 /**
129  *  添加一个子控制器
130  *
131  *  @param childVc           子控制器对象
132  *  @param title             标题
133  *  @param imageName         图标
134  *  @param selectedImageName 选中的图标
135  */
136 - (void)addOneChlildVc:(UIViewController *)childVc title:(NSString *)title imageName:(NSString *)imageName selectedImageName:(NSString *)selectedImageName
137 {
138     // 设置标题
139     childVc.title = title;
140     
141     // 设置图标
142     childVc.tabBarItem.image = [UIImage imageWithName:imageName];
143     
144     // 设置tabBarItem的普通文字颜色
145     NSMutableDictionary *textAttrs = [NSMutableDictionary dictionary];
146     textAttrs[NSForegroundColorAttributeName] = [UIColor blackColor];
147     textAttrs[NSFontAttributeName] = [UIFont systemFontOfSize:10];
148     [childVc.tabBarItem setTitleTextAttributes:textAttrs forState:UIControlStateNormal];
149     
150     // 设置tabBarItem的选中文字颜色
151     NSMutableDictionary *selectedTextAttrs = [NSMutableDictionary dictionary];
152     selectedTextAttrs[NSForegroundColorAttributeName] = [UIColor orangeColor];
153     [childVc.tabBarItem setTitleTextAttributes:selectedTextAttrs forState:UIControlStateSelected];
154     
155     // 设置选中的图标
156     UIImage *selectedImage = [UIImage imageWithName:selectedImageName];
157     if (iOS7) {
158         // 声明这张图片用原图(别渲染)
159         selectedImage = [selectedImage imageWithRenderingMode:UIImageRenderingModeAlwaysOriginal];
160     }
161     childVc.tabBarItem.selectedImage = selectedImage;
162     
163     // 添加为tabbar控制器的子控制器
164     HMNavigationController *nav = [[HMNavigationController alloc] initWithRootViewController:childVc];
165     [self addChildViewController:nav];
166 }
167 
168 #pragma mark - HMTabBarDelegate
169 - (void)tabBarDidClickedPlusButton:(HMTabBar *)tabBar
170 {
171     // 弹出发微博控制器
172     HMComposeViewController *compose = [[HMComposeViewController alloc] init];
173     HMNavigationController *nav = [[HMNavigationController alloc] initWithRootViewController:compose];
174     [self presentViewController:nav animated:YES completion:nil];
175 }
176 @end

 

3:封装导航控制器的代码:

#import <UIKit/UIKit.h>

@interface HMNavigationController : UINavigationController

@end
#import "HMNavigationController.h"

@interface HMNavigationController ()

@end

@implementation HMNavigationController

- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil
{
    self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
    if (self) {
        // Custom initialization
    }
    return self;
}
/**
 *  当导航控制器的view创建完毕就调用
 */
- (void)viewDidLoad
{
    [super viewDidLoad];
    
    // 清空弹出手势的代理,就可以恢复弹出手势
    self.interactivePopGestureRecognizer.delegate = nil;
}

/**
 *  当第一次使用这个类的时候调用1次
 */
+ (void)initialize
{
    // 设置UINavigationBarTheme的主
    [self setupNavigationBarTheme];
    
    // 设置UIBarButtonItem的主题
    [self setupBarButtonItemTheme];
}

/**
 *  设置UINavigationBarTheme的主题
 */
+ (void)setupNavigationBarTheme
{
    UINavigationBar *appearance = [UINavigationBar appearance];
    
    // 设置导航栏背景
    if (!iOS7) {
        [appearance setBackgroundImage:[UIImage imageWithName:@"navigationbar_background"] forBarMetrics:UIBarMetricsDefault];
    }
    
    // 设置文字属性
    NSMutableDictionary *textAttrs = [NSMutableDictionary dictionary];
    textAttrs[UITextAttributeTextColor] = [UIColor blackColor];
    // UITextAttributeFont  --> NSFontAttributeName(iOS7)
#warning 过期 : 并不代表不能用, 仅仅是有最新的方案可以取代它
    textAttrs[UITextAttributeFont] = HMNavigationTitleFont;
    // UIOffsetZero是结构体, 只要包装成NSValue对象, 才能放进字典\数组中
    textAttrs[UITextAttributeTextShadowOffset] = [NSValue valueWithUIOffset:UIOffsetZero];
    [appearance setTitleTextAttributes:textAttrs];
}

/**
 *  设置UIBarButtonItem的主题
 */
+ (void)setupBarButtonItemTheme
{
    // 通过appearance对象能修改整个项目中所有UIBarButtonItem的样式
    UIBarButtonItem *appearance = [UIBarButtonItem appearance];
    
    /**设置文字属性**/
    // 设置普通状态的文字属性
    NSMutableDictionary *textAttrs = [NSMutableDictionary dictionary];
    textAttrs[UITextAttributeTextColor] = [UIColor orangeColor];
    textAttrs[UITextAttributeFont] = [UIFont systemFontOfSize:15];
    textAttrs[UITextAttributeTextShadowOffset] = [NSValue valueWithUIOffset:UIOffsetZero];
    [appearance setTitleTextAttributes:textAttrs forState:UIControlStateNormal];
    
    // 设置高亮状态的文字属性
    NSMutableDictionary *highTextAttrs = [NSMutableDictionary dictionaryWithDictionary:textAttrs];
    highTextAttrs[UITextAttributeTextColor] = [UIColor redColor];
    [appearance setTitleTextAttributes:highTextAttrs forState:UIControlStateHighlighted];
    
    // 设置不可用状态(disable)的文字属性
    NSMutableDictionary *disableTextAttrs = [NSMutableDictionary dictionaryWithDictionary:textAttrs];
    disableTextAttrs[UITextAttributeTextColor] = [UIColor lightGrayColor];
    [appearance setTitleTextAttributes:disableTextAttrs forState:UIControlStateDisabled];
    
    /**设置背景**/
    // 技巧: 为了让某个按钮的背景消失, 可以设置一张完全透明的背景图片
    [appearance setBackgroundImage:[UIImage imageWithName:@"navigationbar_button_background"] forState:UIControlStateNormal barMetrics:UIBarMetricsDefault];
}

/**
 *  能拦截所有push进来的子控制器
 */
- (void)pushViewController:(UIViewController *)viewController animated:(BOOL)animated
{
    if (self.viewControllers.count > 0) { // 如果现在push的不是栈底控制器(最先push进来的那个控制器)
        viewController.hidesBottomBarWhenPushed = YES;
        
        // 设置导航栏按钮
        viewController.navigationItem.leftBarButtonItem = [UIBarButtonItem itemWithImageName:@"navigationbar_back" highImageName:@"navigationbar_back_highlighted" target:self action:@selector(back)];
        viewController.navigationItem.rightBarButtonItem = [UIBarButtonItem itemWithImageName:@"navigationbar_more" highImageName:@"navigationbar_more_highlighted" target:self action:@selector(more)];
    }
    [super pushViewController:viewController animated:animated];
}

- (void)back
{
#warning 这里用的是self, 因为self就是当前正在使用的导航控制器
    [self popViewControllerAnimated:YES];
}

- (void)more
{
    [self popToRootViewControllerAnimated:YES];
}
@end

4:封装tabBar代码:

#import <UIKit/UIKit.h>
@class HMTabBar;

@protocol HMTabBarDelegate <NSObject>

@optional
- (void)tabBarDidClickedPlusButton:(HMTabBar *)tabBar;

@end

@interface HMTabBar : UITabBar
@property (nonatomic, weak) id<HMTabBarDelegate> tabBarDelegate;
@end
#import "HMTabBar.h"

@interface HMTabBar()
@property (nonatomic, weak) UIButton *plusButton;
@end

@implementation HMTabBar

- (id)initWithFrame:(CGRect)frame
{
    self = [super initWithFrame:frame];
    if (self) {
        if (!iOS7) {
            self.backgroundImage = [UIImage imageWithName:@"tabbar_background"];
        }
        self.selectionIndicatorImage = [UIImage imageWithName:@"navigationbar_button_background"];
        
        // 添加加号按钮
        [self setupPlusButton];
    }
    return self;
}

/**
 *  添加加号按钮
 */
- (void)setupPlusButton
{
    UIButton *plusButton = [[UIButton alloc] init];
    // 设置背景
    [plusButton setBackgroundImage:[UIImage imageWithName:@"tabbar_compose_button"] forState:UIControlStateNormal];
    [plusButton setBackgroundImage:[UIImage imageWithName:@"tabbar_compose_button_highlighted"] forState:UIControlStateHighlighted];
    // 设置图标
    [plusButton setImage:[UIImage imageWithName:@"tabbar_compose_icon_add"] forState:UIControlStateNormal];
    [plusButton setImage:[UIImage imageWithName:@"tabbar_compose_icon_add_highlighted"] forState:UIControlStateHighlighted];
    [plusButton addTarget:self action:@selector(plusClick) forControlEvents:UIControlEventTouchUpInside];
    // 添加
    [self addSubview:plusButton];
    self.plusButton = plusButton;
}

- (void)plusClick
{
    HMLog(@"plusClick----");
    
    // 通知代理
    if ([self.tabBarDelegate respondsToSelector:@selector(tabBarDidClickedPlusButton:)]) {
        [self.tabBarDelegate tabBarDidClickedPlusButton:self];
    }
}

/**
 *  布局子控件
 */
- (void)layoutSubviews
{
    [super layoutSubviews];
    
    // 设置plusButton的frame
    [self setupPlusButtonFrame];
    
    // 设置所有tabbarButton的frame
    [self setupAllTabBarButtonsFrame];
}

/**
 *  设置所有plusButton的frame
 */
- (void)setupPlusButtonFrame
{
    self.plusButton.size = self.plusButton.currentBackgroundImage.size;
    self.plusButton.center = CGPointMake(self.width * 0.5, self.height * 0.5);
}

/**
 *  设置所有tabbarButton的frame
 */
- (void)setupAllTabBarButtonsFrame
{
    int index = 0;
    
    // 遍历所有的button
    for (UIView *tabBarButton in self.subviews) {
        // 如果不是UITabBarButton, 直接跳过
        if (![tabBarButton isKindOfClass:NSClassFromString(@"UITabBarButton")]) continue;
        
        // 根据索引调整位置
        [self setupTabBarButtonFrame:tabBarButton atIndex:index];
        
        // 索引增加
        index++;
    }
}

/**
 *  设置某个按钮的frame
 *
 *  @param tabBarButton 需要设置的按钮
 *  @param index        按钮所在的索引
 */
- (void)setupTabBarButtonFrame:(UIView *)tabBarButton atIndex:(int)index
{
    // 计算button的尺寸
    CGFloat buttonW = self.width / (self.items.count + 1);
    CGFloat buttonH = self.height;
    
    tabBarButton.width = buttonW;
    tabBarButton.height = buttonH;
    if (index >= 2) {
        tabBarButton.x = buttonW * (index + 1);
    } else {
        tabBarButton.x = buttonW * index;
    }
    tabBarButton.y = 0;
}
@end

5:封装UIBarButtonItem:分类封装

//自定义图片按钮:常态,高亮状态

#import <UIKit/UIKit.h>

@interface UIBarButtonItem (Extension)
+ (UIBarButtonItem *)itemWithImageName:(NSString *)imageName highImageName:(NSString *)highImageName target:(id)target action:(SEL)action;
@end
#import "UIBarButtonItem+Extension.h"

@implementation UIBarButtonItem (Extension)
+ (UIBarButtonItem *)itemWithImageName:(NSString *)imageName highImageName:(NSString *)highImageName target:(id)target action:(SEL)action
{
    UIButton *button = [[UIButton alloc] init];
    [button setBackgroundImage:[UIImage imageWithName:imageName] forState:UIControlStateNormal];
    [button setBackgroundImage:[UIImage imageWithName:highImageName] forState:UIControlStateHighlighted];
    
    // 设置按钮的尺寸为背景图片的尺寸
    button.size = button.currentBackgroundImage.size;
    
    // 监听按钮点击
    [button addTarget:target action:action forControlEvents:UIControlEventTouchUpInside];
    return [[UIBarButtonItem alloc] initWithCustomView:button];
}
@end

6:封装UIView的frame:分类封装

#import <UIKit/UIKit.h>

@interface UIView (Extension)
@property (nonatomic, assign) CGFloat x;
@property (nonatomic, assign) CGFloat y;
@property (nonatomic, assign) CGFloat centerX;
@property (nonatomic, assign) CGFloat centerY;
@property (nonatomic, assign) CGFloat width;
@property (nonatomic, assign) CGFloat height;
@property (nonatomic, assign) CGSize size;
@end
#import "UIView+Extension.h"

@implementation UIView (Extension)

- (void)setX:(CGFloat)x
{
    CGRect frame = self.frame;
    frame.origin.x = x;
    self.frame = frame;
}

- (CGFloat)x
{
    return self.frame.origin.x;
}

- (void)setY:(CGFloat)y
{
    CGRect frame = self.frame;
    frame.origin.y = y;
    self.frame = frame;
}

- (CGFloat)y
{
    return self.frame.origin.y;
}

- (void)setCenterX:(CGFloat)centerX
{
    CGPoint center = self.center;
    center.x = centerX;
    self.center = center;
}

- (CGFloat)centerX
{
    return self.center.x;
}

- (void)setCenterY:(CGFloat)centerY
{
    CGPoint center = self.center;
    center.y = centerY;
    self.center = center;
}

- (CGFloat)centerY
{
    return self.center.y;
}

- (void)setWidth:(CGFloat)width
{
    CGRect frame = self.frame;
    frame.size.width = width;
    self.frame = frame;
}

- (CGFloat)width
{
    return self.frame.size.width;
}

- (void)setHeight:(CGFloat)height
{
    CGRect frame = self.frame;
    frame.size.height = height;
    self.frame = frame;
}

- (CGFloat)height
{
    return self.frame.size.height;
}

- (void)setSize:(CGSize)size
{
//    self.width = size.width;
//    self.height = size.height;
    CGRect frame = self.frame;
    frame.size = size;
    self.frame = frame;
}

- (CGSize)size
{
    return self.frame.size;
}

@end

 

 

 

 

 

 

 

三:思路分析:

1:先添加首页,信息,发现,我四个控制器为根视图控制器的子控制器,在viewDidload方法里封装方法[self addAllChildVcs];调用。因为四个子控制器中每个子控制器都要设置title,Vc.tabBarItem.image,Vc.abBarItem.selectedImage,以及abBarItem的文字属性,还要包装一层导航控制器,最后addChildViewController作为根视图控制器的子控制器。此时会有大量重复的代码,所以要想抽取代码的思想,将大量重复的代码抽成一个方法,把相同的代码封装在方法的内部,不同的部分作为参数传递。所以将此段代码抽成一个方法:- (void)addOneChlildVc:(UIViewController *)childVc title:(NSString *)title imageName:(NSString *)imageName selectedImageName:(NSString *)selectedImageName;创建出子控制器对象后,将子控制器对象,title,image ,selectedImage作为参数传递。

2:设置tabItem的文字属性:1:在封装方法中,设置标题属性, childVc.title = title;此句代码既设置了tabBaritem上的标题,也设置了相应子控制器的导航栏的标题。设置tabBar上不同状态下的标题的文字属性:利用方法 setTitleTextAttributes:dic  forState:state 就可以设置不同状态下的文字属性,常态,高亮,失效。(给字典赋值:dic[key]= value;dic为可变字典)

    NSMutableDictionary *textAttrs = [NSMutableDictionary dictionary];

    textAttrs[NSForegroundColorAttributeName] = [UIColor blackColor];

    textAttrs[NSFontAttributeName] = [UIFont systemFontOfSize:10];

    [childVc.tabBarItem setTitleTextAttributes:textAttrs forState:UIControlStateNormal];

 3:设置tabItem上不同状态下的图片属性:1:Normal :childVc.tabBarItem.image = [UIImage imageWithName:imageName];  2:selected: UIImage *selectedImage = [UIImage imageWithName:selectedImageName];

    if (iOS7) {

        // 声明这张图片用原图(别渲染)        selectedImage = [selectedImage imageWithRenderingMode:UIImageRenderingModeAlwaysOriginal];    }

    childVc.tabBarItem.selectedImage = selectedImage;

1:判断是否是ios7,可以在pch文件中做宏定义,其中一些宏定义,一些头文件都可以在pch中做定义。

#define iOS7 ([[UIDevice currentDevice].systemVersion doubleValue] >= 7.0)

2:对于NSLog的宏定义也可以在pch中:

1 #ifdef DEBUG  //调式状态
2 #define DLog(...) NSLog (__VA_ARGS__)
3 #else //发布状态
4 #define DLog (...)
5 #endif

3:单例的宏定义:

//单例的宏定义:斜线向右,表示下一行也属于宏定义
#define Single_interface(className)  +(className*)shared##className

#define Single_implemtation(className) +(className*)shared##className { \
\
static className *instance = nil;\
static dispatch_once_t onceToken;\
dispatch_once(&onceToken, ^{\
 \
    instance = [[self alloc]init];\
});\
\
return instance;\
}

4:在系统大于或等于ios7时,系统默认会对系统的一些控件产生渲染,渲染为蓝色,例如button为系统样式时,会被渲染为蓝色,而tabBarItem上的图片,normal状态下不会被渲染,只有是选中selected状态下才会被渲染成蓝色。解决办法:三部曲:1:先创建图片 2:判断是否为ios7若是则调用UIImage的方法imageWithRenderingMode,告诉系统不要渲染,保持原图,并返回一张原图的图片。selectedImage = [selectedImage imageWithRenderingMode:UIImageRenderingModeAlwaysOriginal]; 3:设置tabBarietm上的选中图片 

UIImage *selectedImage = [UIImage imageWithName:selectedImageName];
    if (iOS7) {
        // 声明这张图片用原图(别渲染)
        selectedImage = [selectedImage imageWithRenderingMode:UIImageRenderingModeAlwaysOriginal];
    }
    childVc.tabBarItem.selectedImage = selectedImage;

5:给每一个子控制器包装一层导航控制,主要自定义导航控制器,为了设置导航控制器上item的属性。新建类继承UINavigationController。1:因为只要是自定义了导航控制器,则系统的侧滑返回效果就会消失,只要在viewDidLoad里将手势代理清空即可:self.interactivePopGestureRecognizer.delegate = nil;

2:自定义UINavigationBar 和 UIBarButtonItem:1:其中UINavigationBar为整个导航栏,设置其主体主要设置的是导航栏的背景色,背景图片,title文字的属性。UIBarButtonItem:设置的是导航栏上左右按钮的图片或是文字属性。3:UINavigationBar *appearance = [UINavigationBar appearance];UIBarButtonItem *appearance = [UIBarButtonItem appearance];通过appearance方法返回的两个对象是全局对象,通过设置这两个对象的属性,就可以达到整个项目中全局设置,因为在整个项目中只需要设置一次,所以不需要在ViewDidload里去设置,因为没创建一次对象,ViewDidload就会调用一次,这样导航栏的主题就会被重复设置,所以将设置导航栏主题的方法封装在,+ (void)initialize,该方法只会在该类第一次使用,也就是该类的第一个方法被调用之前调用,有且只调用一次。在内部封装的方法应为类方法,用self去调用,在类方法中self指向的是当前的类,在对象方法中self指向的是当前的对象。


3:设置UINavigationBar属性:获得全局导航栏对象appearance,1:可以设置其背景色tintColor ,2:背景图片:setBackgroundImage forBarMetrics: 第二个参数为默认即可  2:设置title的文字属性: [appearance setTitleTextAttributes:textAttrs];不用设置状态。(在开发中有些方法是过期会有警告,其实也能用,只不过是有新的方法可以代替它),设置title字体的偏移量也就是阴影效果,textAttrs[NSShadowAttributeName] = [NSValue valueWithUIOffset:UIOffsetZero];其中CGRect,CGPoint,UIOffset 都是结构体,只有封装成NSValue对象,才可以放到数组或是字典中。

4:设置UIBarButtonItem的主题:1:UIBarButtonItem也就是导航栏上的左右按钮,可以利用setTitleTextAttributes 

forState 属性分别设置左右按钮的常态,高亮,失效状态下的文字属性。2:当左右按钮为一张图片时,给UIBarButtonItem写一个分类,设置customView自定义按钮,直接设置按钮的背景图片为该张图片就可以。

5:重写导航控制器的push方法:1:目的是拦截push方法,因为每个栈里的控制器,左右按钮都相同,所以不需要再栈里每个控制器里创建左右按钮。拦截导航控制器的push方法,当压栈的时候,就为每个即将压栈的控制器设置了左右按钮。2:在将四个主控制器包装导航控制器的时候,initWithrootViewController,已经把该四个控制器压入栈里,此时会调用导航控制器的push方法,

/**
 *  能拦截所有push进来的子控制器
 */
- (void)pushViewController:(UIViewController *)viewController animated:(BOOL)animated
{
    if (self.viewControllers.count > 0) { // 如果现在push的不是栈底控制器(最先push进来的那个控制器)
        viewController.hidesBottomBarWhenPushed = YES;
        
        // 设置导航栏按钮
        viewController.navigationItem.leftBarButtonItem = [UIBarButtonItem itemWithImageName:@"navigationbar_back" highImageName:@"navigationbar_back_highlighted" target:self action:@selector(back)];
        viewController.navigationItem.rightBarButtonItem = [UIBarButtonItem itemWithImageName:@"navigationbar_more" highImageName:@"navigationbar_more_highlighted" target:self action:@selector(more)];
    }
    [super pushViewController:viewController animated:animated];
}

1:重写的push方法,1:传入的viewController为即将压栈的控制器,重写系统的方法,不要忘记调用super。super方法在左后调用,是避免为四个主控制器也设置左右按钮 2:拿到导航控制器栈里的子控制器数组:nav.viewControllers(self.viewControllers),判断子控制器数组里的控制器个数 > 0,则表示不是栈底控制器。此时可以拿到即将压栈的控制器设置左右item:viewController.navigationItem.leftBarButtonItem。2:对左右按钮为图片的直接将图片设置为btn的背景图片,给UIBarButtonItem写一个分类,传入normalImage ,HighlightedImage,target,action,自定义btn,设置不同状态下的背景图片,一般对于图片按钮来说,按钮的大小就设置为图片的大小。对于button来说,获得当前的image,title,backgroundImage的方法,btn.currentTtitle,btn.currentImage,btn.currentBackgroundImage 3:若想调整左右按钮距离屏幕的左右间距:可以自定navbar继承系统的bar,重写layoutSubView方法,遍历子控件数组,分别找到左右按钮,调整左右按钮的frame。再利用kvc的setValue forKeyPath,来替换掉系统的navBar(只需创建自定义bar的对象,因为继承于系统,所以系统所声明的非私有的属性方法变量都会继承,不用设置frame,第一个参数为创建的自定义navbar对象,第二个参数为导航控制器或是tabbar控制器下的navbar,或是tabbar以属性定义的对象) 4:当push压栈的时候,需要隐藏tabBar,此时可在拦截的push方法中,拿到即将压栈的控制器,调用

 //0:当push的时候隐藏dock栏 viewController.hidesBottomBarWhenPushed = YES;

2:自定义tabBar的封装:1:+(instancetype)tabBar;return [self alloc ]init]; 类方法快速返回一个对象,alloc内部会调用alloc initWithFrame方法,所以重写alloc initWithFrame方法,在此方法内先设置自身的属性:可以设置tabbar的背景图片self.backgroundImage 或是选中的背景图片,self.selectionIndicatorImage = [UIImage imageWithName:@"navigationbar_button_background"];2:懒加载子控件,设置控件的属性,将控件添加到父视图上。创建中间的加号按钮,常态,高亮状态下的背景图片,setImage设置常态高亮状态下的图片,添加监听,添加到父视图上。3:在layoutSubView里设置控件的frame,(若为图片按钮,有不同状态,就设图片为整个按钮背景,分贝设常态,高亮,选中状态下的背景图片,按钮的大小为图片的大小:btn.currentTitle,btn.currentImage,btn.currentBackgroundImage即可获得当前显示的图片和标题。)如何拿到控件设置frame,1:属性,成员变量,枚举tag值 2:大数组思想:装在大数组,当一个控件上分别有不同的控件的时候,可以两两分别装在数组里,用到的时候再从数组里取出 3:继承UIView的可以遍历self.subViews,遍历子控件的数组,做条件过滤,找到停止遍历。若是UIScrollView,会多出两个控件横竖滚动条,直接隐藏就不会显示了,隐藏后可直接遍历子控件数组,也可以提前给View设置tag值,当遍历时,找到父view后,通过tag值将view取出 。当父view上有多个控件时,还可以遍历子控件数组,做过滤,当找到需要设置frame的控件后,需要根据index设置frame,此时在循环中无法拿到index,就自己定义一个index,找到控件后执行index++,根据控件的索引来设置frame 4:设置按钮的tag值:1:直接设置(可为0)2:枚举tag值,用于按钮的回调,根据枚举值判断是哪个按钮 3:btn.tag =self.subViews.count,适用于将按钮取出,或是应用于本类中 。4:所以设置加号按钮的size为图片的size,通过btn.currentBackgroundImage把图片取出(一般给系统控件赋值时,调用的是系统控件的set方法,若想在其他地方获得该值,可以调用其系统控件的get方法,例如btn的三个方法,lable.font,vc.title等),如果控件需要居中显示的话,就设置控件的center属性,例如新特性界面的pageControl的frame设置方法。5:虽然是自定义的tabBar,但是继承的是系统的tabBar,已经添加了四个子控制器,所以自定义的tabbar上已经添加了四个按钮。需要重新调整四个按钮的距离。在layoutSubView里重新调整四个按钮的frame。遍历子控件数组,做条件过滤,并打印,有的是系统没有声明的属性,打印出只是一个字符串,利用NSSClassFromString();方法将字符串转化为类来判断是否属于.

/**
 *  设置所有tabbarButton的frame
 */
- (void)setupAllTabBarButtonsFrame
{
    int index = 0;
    
    // 遍历所有的button
    for (UIView *tabBarButton in self.subviews) {
        // 如果不是UITabBarButton, 直接跳过
        if (![tabBarButton isKindOfClass:NSClassFromString(@"UITabBarButton")]) continue;
        
        // 根据索引调整位置
        [self setupTabBarButtonFrame:tabBarButton atIndex:index];
        
        // 索引增加
        index++;
    }
}

/**
 *  设置某个按钮的frame
 *
 *  @param tabBarButton 需要设置的按钮
 *  @param index        按钮所在的索引
 */
- (void)setupTabBarButtonFrame:(UIView *)tabBarButton atIndex:(int)index
{
    // 计算button的尺寸
    CGFloat buttonW = self.width / (self.items.count + 1);
    CGFloat buttonH = self.height;
    
    tabBarButton.width = buttonW;
    tabBarButton.height = buttonH;
    if (index >= 2) {
        tabBarButton.x = buttonW * (index + 1);
    } else {
        tabBarButton.x = buttonW * index;
    }
    tabBarButton.y = 0;
}
@end

设置frame的思路:1:tabBar上已经添加上了5个按钮,就让这5个按钮评分tabBar的宽度,注意:self.ietms.count,虽然此时tabBar已经有5个按钮了,但是个数为4,它指的是加入tabBarcontroller中的子控制器的个数。高度为自身tabBar的高度,y值为0,x值的设置,前两个可以根据索引正常设置buttonW * index,到后两个的时候:buttonW * (index + 1)。2:当在layoutSubView里设置frame时,遍历取出控件,根据index设置frame,如果无法遍历,可以自己构造index,实现index++,将index传过去。

5:tabBar点击中间加号按钮的回调:1:回调可用协议代理,block ,通知,前两个用于层级较浅的回调,通知适用于层级较深的回调 2:其中两个控制器需要回调数据时,若两个控制器需要实时相互回调数据,可用block和协议代理,设置返回值,当一端回调数据后,处理完数据后,还可以返回一些给原控制器提供回调数据。3:协议代理的方法默认为@require,注意协议代书写的规范性,仿照tableView的代理来设置

6:在tabBarController里利用kvc替换系统的tabBar:不用设置frame

/**
 *  创建自定义tabbar
 */
- (void)addCustomTabBar
{
    // 创建自定义tabbar
    HMTabBar *customTabBar = [[HMTabBar alloc] init];
    customTabBar.tabBarDelegate = self;
    // 更换系统自带的tabbar
    [self setValue:customTabBar forKeyPath:@"tabBar"];
}

7:UIImage的封装:分类封装

#import <UIKit/UIKit.h>

@interface UIImage (Extension)
/**
 *  根据图片名自动加载适配iOS6\7的图片
 */
+ (UIImage *)imageWithName:(NSString *)name;

/**
 *  根据图片名返回一张能够自由拉伸的图片
 */
+ (UIImage *)resizedImage:(NSString *)name;
@end
#import "UIImage+Extension.h"

@implementation UIImage (Extension)
+ (UIImage *)imageWithName:(NSString *)name
{
    UIImage *image = nil;
    if (iOS7) { // 处理iOS7的情况
        NSString *newName = [name stringByAppendingString:@"_os7"];
        image = [UIImage imageNamed:newName];
    }
    
    if (image == nil) {
        image = [UIImage imageNamed:name];
    }
    return image;
}

+ (UIImage *)resizedImage:(NSString *)name
{
    UIImage *image = [UIImage imageWithName:name];
    return [image stretchableImageWithLeftCapWidth:image.size.width * 0.5 topCapHeight:image.size.height * 0.5];
}
@end

赋值代码的三部曲:1:外部先定义一个变量 2:中间根据判断条件拿到变量赋值 3:重新给变量赋值(若判断条件不符合,则变量的值没有改变,若是符合,则发生了改变)