美文网首页iOS点点滴滴iOS Developer
自定义YWTabBarViewController

自定义YWTabBarViewController

作者: Wang66 | 来源:发表于2016-02-02 17:04 被阅读408次

    前言

    今天是春节前最后一天班了,晚上收拾东西回家。最后一天就好好做件事,写点东西。然后回家过个好年。

    自定义YWTabBarViewController

    先看最终效果图:

    tabBarController.gif

    首先需要明了的是APP一启动便有下面的tabBar,所以tabBarController得在整个APP的rootViewController创建添加。
    所以,我们创建了我们项目的RootViewController,并设置为整个APP的rootViewController。

    - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
     {
        RootViewController *rootVC = [[RootViewController alloc] init];
        UINavigationController *rootNavC = [[UINavigationController alloc] initWithRootViewController:rootVC];
        self.window.rootViewController = rootNavC;
        
        return YES;
    }
    

    我们再来看看RootViewController里:
    可以看到我们通过我们自定义的YWTabBarViewController类,将tabBarController这个容器里视图添加到了RootViewController上,并设置默认选中第一个按钮。而且还实现了tabBarController的代理方法。

    #import "RootViewController.h"
    #import "YWTabBarViewController.h"
    #import "AAAViewController.h"
    #import "BBBViewController.h"
    #import "CCCViewController.h"
    
    
    @interface RootViewController ()<YWTabBarControllerDelegate>
    {
        YWTabBarViewController          *_tabBarVC;
    }
    @property (nonatomic, strong)NSArray            *vcsArr;
    
    
    @end
    
    @implementation RootViewController
    
    - (void)viewDidLoad
    {
        [super viewDidLoad];
        self.title = @"root";
        self.navigationController.navigationBar.hidden = YES;
        _tabBarVC = [[YWTabBarViewController alloc] initWithViewControllers:[self vcsArr] imagesArr:[self imagesArr]];
        _tabBarVC.selectedIndex = 0;
        _tabBarVC.delegate = self;
        
        [self.view addSubview:_tabBarVC.view];
    }
    
    
    
    
    #pragma mark ---- private method
    
    - (NSMutableArray *)imagesArr
    {
        NSArray *imageNames=[NSArray arrayWithObjects:
                             [NSArray arrayWithObjects:@"bottomBar_home.png",@"bottomBar_home1.png",@"bottomBar_home1.png", nil],
                             [NSArray arrayWithObjects:@"bottomBar_agency.png",@"bottomBar_agency1.png",@"bottomBar_agency1.png", nil],
                             [NSArray arrayWithObjects:@"bottomBar_act.png",@"bottomBar_act1.png",@"bottomBar_act1.png", nil] ,nil];
        
        NSMutableArray *imgArr=[[NSMutableArray alloc]init];
        for (int i=0; i<imageNames.count; i++)
        {
            NSArray *names=[imageNames objectAtIndex:i];
            NSMutableDictionary *imgDic= [NSMutableDictionary dictionaryWithCapacity:3];
            [imgDic setObject:[UIImage imageNamed:[names objectAtIndex:0]]  forKey:@"Default" ];
            [imgDic setObject:[UIImage imageNamed:[names objectAtIndex:1]] forKey:@"Highlighted"];
            [imgDic setObject:[UIImage imageNamed:[names objectAtIndex:2]] forKey:@"Seleted"];
            
            [imgArr addObject:imgDic];
        }
        
        return imgArr;
    }
    
    
    - (NSArray *)vcsArr
    {
        AAAViewController *aaaVC = [[AAAViewController alloc] init];
        UINavigationController *navCAAA = [[UINavigationController alloc] initWithRootViewController:aaaVC];
        BBBViewController *bbbVC = [[BBBViewController alloc] init];
        UINavigationController *navCBBB = [[UINavigationController alloc] initWithRootViewController:bbbVC];
        CCCViewController *cccVC = [[CCCViewController alloc] init];
        UINavigationController *navCCCC = [[UINavigationController alloc] initWithRootViewController:cccVC];
        
        return @[navCAAA, navCBBB, navCCCC];
    }
    
    
    #pragma mark ---- tabBarController delegate
    
    - (BOOL)ywtabBarViewController:(YWTabBarViewController *)tabBarController shouldSelectViewController:(UIViewController *)viewController
    {
        for(UINavigationController *navC in [self vcsArr])
        {
            if(navC != viewController){
                [navC popToRootViewControllerAnimated:YES];
            }else{
                if(navC.viewControllers.count>0){
                    
                }
            }
        }
        return YES;
    }
    
    
    - (void)ywtabBarViewController:(YWTabBarViewController *)tabBarController didSelectViewController:(UIViewController *)viewController
    {
        NSLog(@"xxxx");
    }
    
    @end
    

    然后我们再看看YWTabBarViewController究竟是怎样写的:

    ** YWTabBarViewController.h **
    #import <UIKit/UIKit.h>
    
    @class YWTabBarViewController;
    @protocol YWTabBarControllerDelegate <NSObject>
    
    - (BOOL)ywtabBarViewController:(YWTabBarViewController *)tabBarController shouldSelectViewController:(UIViewController *)viewController;
    - (void)ywtabBarViewController:(YWTabBarViewController *)tabBarController didSelectViewController:(UIViewController *)viewController;
    
    @end
    
    @interface YWTabBarViewController : UIViewController
    
    
    @property (nonatomic, assign)NSUInteger             selectedIndex;
    
    @property (nonatomic, weak)id<YWTabBarControllerDelegate>   delegate;
    
    - (instancetype)initWithViewControllers:(NSArray *)vcsArr imagesArr:(NSArray *)imgsArr;
    
    @end
    
    ** YWTabBarViewController.m **

    代码里写了很多注释,基本很清楚了。但是还有几点重要部分仍需要说一下。
    1.自定义东西,首先要面临的就是写初始化方法。初始化方法应该写得使调用者做尽量少的事,让调用者感到清晰明了,且简单易用。
    2.其实tabBarController最重要的逻辑就是切换下面tabBar时,tabBar的按钮状态和_mainView视图同时做相应的切换。在代码里由- (void)displayViewAtIndex:(NSUInteger)index完成这个逻辑。
    3.tabBarController暴露给外部一个selectedIndex属性,外部传入该属性参数,tabBarControler内部由selectedIndex的值来判断按钮状态及相应的_mainView。我们重写了selectedIndex的setter方法,只要我们在外部_tabBarVC.selectedIndex = 1;便会调用内部方法,完成tabBar按钮状态的改变和相应视图的显示。

    #import "YWTabBarViewController.h"
    #import "YWTabBar.h"
    
    @interface YWTabBarViewController ()<YWTabBarDelegate>
    {
        NSArray         *_vcsArr;
        NSArray         *_imgsArr;
        
        UIView          *_containView;
        UIView          *_mainView;
        YWTabBar          *_ywTabBar;
    }
    @end
    
    @implementation YWTabBarViewController
    
    
    #pragma mark ---- life cycle
    
    - (instancetype)initWithViewControllers:(NSArray *)vcsArr imagesArr:(NSArray *)imgsArr
    {
        self = [super init];
        if(self)
        {
            _vcsArr = [NSArray arrayWithArray:vcsArr];  // tabBarController容器类里的viewController们
            _imgsArr = [NSArray arrayWithArray:imgsArr]; // 各个viewController的图片资源
            
            CGRect rect = [UIScreen mainScreen].bounds;
            _containView = [[UIView alloc] initWithFrame:rect];
            self.view = _containView; // 占满整个屏幕
            
            _mainView = [[UIView alloc] initWithFrame:CGRectMake(0, 0, MainScreen_W, MainScreen_H-TabBar_H)];
            _mainView.backgroundColor = [UIColor groupTableViewBackgroundColor];
            [_containView addSubview:_mainView];
            
            _ywTabBar = [[YWTabBar alloc] initWithFrame:CGRectMake(0, MainScreen_H-TabBar_H, MainScreen_W, TabBar_H)
                                           imgagesArray:imgsArr];
            _ywTabBar.backgroundColor = [UIColor whiteColor];
            _ywTabBar.delegate = self;
            [_containView addSubview:_ywTabBar];
            
        }
        
        return self;
    }
    
    
    
    - (void)viewDidLoad {
        [super viewDidLoad];
        // Do any additional setup after loading the view.
    }
    
    
    
    #pragma mark ---- tabBar delegate
    
    - (void)ywtabBar:(YWTabBar *)tabBar didSelectIndex:(NSUInteger)index
    {
        [self displayViewAtIndex:index];
    }
    
    
    #pragma mark ---- function method
    
    // 显示响应的viewController
    // (重点)控制当tabBar点击时显示相应的viewController的view
    - (void)displayViewAtIndex:(NSUInteger)index
    {
        if([_delegate respondsToSelector:@selector(ywtabBarViewController:shouldSelectViewController:)])
        {
            if(![_delegate ywtabBarViewController:self shouldSelectViewController:_vcsArr[index]])
            {
                [_ywTabBar tabBarSelectAtIndex:index];  // 切换tabBar按钮的高亮状态
            }
        }
    
    //--------- 根据点击tabBar的index来相应的显示视图
        _selectedIndex = index;
        
        UIViewController *selectedVC = _vcsArr[index];
        selectedVC.view.frame = _mainView.frame;
    // 每切换一个vc,便将其view添加在_mainView上,等vc都被切换过了其实它们都已被添加在_mainView上。然后再次切换某个vc,实际上就是将其view移动到最上层。
        if([selectedVC.view isDescendantOfView:_mainView]) // 判断selectedVC.view是否是_mainView上的视图
        {
            [_mainView bringSubviewToFront:selectedVC.view];
        }else{
            [_mainView addSubview:selectedVC.view];
        }
    //---------
        
        // 并调用YWTabBarViewController的代理方法,在RootViewController实现时做些其他处理。
        if([_delegate respondsToSelector:@selector(ywtabBarViewController:didSelectViewController:)])
        {
            [_delegate ywtabBarViewController:self didSelectViewController:_vcsArr[index]];
        }
    }
    
    
    
    
    #pragma mark ---- setter/getter
    
    // 重写selectedIndex属性的setter方法,在内控制切换时tabBar按钮的状态和相应视图的显示。
    - (void)setSelectedIndex:(NSUInteger)selectedIndex
    {
        [_ywTabBar tabBarSelectAtIndex:selectedIndex];
        [self displayViewAtIndex:selectedIndex];
    }
    
    @end
    

    我们是把tabBar独立建了类YWTabBar,在其内部完成了视图布局,逻辑处理等。我们来看看YWTabBar是怎样写的:

    ** YWTabBar.h **
    #import <UIKit/UIKit.h>
    
    @class YWTabBar;
    @protocol YWTabBarDelegate <NSObject>
    
    - (void)ywtabBar:(YWTabBar *)tabBar didSelectIndex:(NSUInteger)index;
    
    @end
    
    
    
    @interface YWTabBar : UIView
    
    @property (nonatomic, weak)id<YWTabBarDelegate>     delegate;
    
    - (instancetype)initWithFrame:(CGRect)frame imgagesArray:(NSArray *)imgsArr;
    
    // 只是改变按钮的状态
    - (void)tabBarSelectAtIndex:(NSUInteger)selectIndex;
    
    @end
    
    ** YWTabBar.m **
    #import "YWTabBar.h"
    
    @interface YWTabBar ()
    {
        CGRect                           _frame;
        NSArray                         *_imgsArr;
        NSMutableArray                  *_btnsArr;
        UIImageView                     *_backgroudImage;
        NSUInteger                       _selectedIndex;
    }
    
    @end
    
    
    @implementation YWTabBar
    
    - (instancetype)initWithFrame:(CGRect)frame
    {
        self = [super initWithFrame:frame];
        if(self)
        {
            // 对于系统的初始化方法,重写但置空
        }
        return self;
    }
    
    - (instancetype)initWithFrame:(CGRect)frame imgagesArray:(NSArray *)imgsArr
    {
        self = [super initWithFrame:frame];
        if(self)
        {
            _frame = frame;
            _imgsArr = [NSArray arrayWithArray:imgsArr];
            _selectedIndex = 0; 
            _btnsArr = [[NSMutableArray alloc] init];
            [self loadContentView];
        }
        return self;
        
    }
    
    // tabBar的视图布局
    - (void)loadContentView
    {
        _backgroudImage = [[UIImageView alloc] initWithFrame:CGRectMake(0, 0, MainScreen_W, TabBar_H)];
        _backgroudImage.userInteractionEnabled = YES;
        [self addSubview:_backgroudImage];
        
        for(int i=0; i<_imgsArr.count; i++)
        {
            NSDictionary *dict = _imgsArr[i];
            UIButton *btn = [[UIButton alloc] initWithFrame:CGRectMake(_frame.size.width/_imgsArr.count*i , 0, _frame.size.width/_imgsArr.count, TabBar_H)];
            [btn setImage:dict[@"Default"] forState:UIControlStateNormal];
            [btn setImage:dict[@"Highlighted"] forState:UIControlStateHighlighted];
            [btn setImage:dict[@"Seleted"] forState:UIControlStateSelected];
            [btn setBackgroundColor:[UIColor greenColor]];
            btn.userInteractionEnabled = YES;
            btn.showsTouchWhenHighlighted = YES;
            btn.tag = i;
            [btn addTarget:self action:@selector(tabBarBtnClick:) forControlEvents:UIControlEventTouchUpInside];
            [_backgroudImage addSubview:btn];
            [_btnsArr addObject:btn];
        }
    }
    
    
    #pragma mark ---- event response
    
    - (void)tabBarBtnClick:(UIButton *)btn
    {
        NSUInteger tag = btn.tag;
        [self tabBarSelectAtIndex:tag];  // tabBar的btn状态变化
        
        if([self.delegate respondsToSelector:@selector(ywtabBar:didSelectIndex:)])
        {
            [self.delegate ywtabBar:self didSelectIndex:tag]; // 对于相应视图的切换,则由代理完成。即YWTabBarViewController里的displayViewAtIndex:
        }
    }
    
    
    
    #pragma mark ---- function method
    // 只是改变按钮的状态
    - (void)tabBarSelectAtIndex:(NSUInteger)selectIndex
    {
        for(int i=0; i<_btnsArr.count; i++)
        {
            UIButton *btn = _btnsArr[i];
            btn.selected = NO;
            btn.userInteractionEnabled = YES;
            
            if(i == selectIndex){
                btn.selected = YES;
                btn.userInteractionEnabled = NO;
            }
        }
    }
    
    @end
    

    相关文章

      网友评论

        本文标题:自定义YWTabBarViewController

        本文链接:https://www.haomeiwen.com/subject/fzaskttx.html