• 三:新浪微博--主框架的搭建


    一:主框架分析:

    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)
    /**
     *  根据图片名自动加载适配iOS67的图片
     */
    + (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:重新给变量赋值(若判断条件不符合,则变量的值没有改变,若是符合,则发生了改变)

  • 相关阅读:
    antd表单验证图片 必须上传
    interface和type的区别
    Typescript+React封装路由拦截组件
    redux和sessionStorage,localStorage的区别
    ES6中数组和对象的扩展运算符拷贝问题以及常用的深浅拷贝方法
    从变量提升角度看待暂时性死区
    MySQL修改root密码
    用VScode配置Python开发环境
    element UI 制作带月份快捷选项的时间选择器
    React v16.4 的生命周期
  • 原文地址:https://www.cnblogs.com/cqb-learner/p/5737914.html
Copyright © 2020-2023  润新知