iOS点点滴滴iOS Developer

自定义YWTabBarViewController

2016-02-02  本文已影响408人  Wang66

前言

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

自定义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
上一篇下一篇

猜你喜欢

热点阅读