zoukankan      html  css  js  c++  java
  • 【iOS】自己定义TabBarController

    一、自己定义的思路

    iOS中的TabBarController确实已经非常强大了。大部分主流iOS应用都会採用。

    可是往往也不能满足所有的需求,因此须要自己定义TabBar,自己定义须要对系统的TabBar工作方式有非常好的理解,自己定义须要勇气。

    自己定义TabBar的原则:尽量利用系统自带TabBar,仅仅改须要改的地方。


    二、自己定义TabBar的整体过程
    1.先把自带的TabBar条给取消了
    2.自己做一个view,上面放几个button,设定button的点击事件.并设置selectIndex。

    3.关联各个子viewController。覆盖相关事件。

    三、细节非常重要

    1. 让自己创建的button关联到viewController:
    tabbarselectedIndex属性.设置这个属性即可了.
    2. 取消系统的高亮:
    能够自己定义一个button.重写里面的setHighhighted方法,什么也不做即可了.(假设调用super就相当于没写)
    3. 关于几个button仅仅选中一个的方法:
    设置一个属性,记录上一个选中的button.
    点击当前button时,把上一个button设置为未选中,并把当前button设置为选中,最后把当前button赋值给上一个button.

    四、初步自己定义
    直接上代码,详见凝视。
    XNTabBarController.h

    #import <UIKit/UIKit.h>
    
    @interface XNTabBarController : UITabBarController
    
    @end

    XNTabBarController.m

    //
    //  XNTabBarController.m
    //
    //
    //  Created by neng on 14-6-19.
    //  Copyright (c) 2014年 neng. All rights reserved.
    //
    
    #import "XNTabBarController.h"
    #import "Common.h"
    #import "XNTabBarButton.h"
    
    @interface XNTabBarController ()
    /**
     *  设置之前选中的button
     */
    @property (nonatomic, weak) UIButton *selectedBtn;
    @end
    
    @implementation XNTabBarController
    
    - (void)viewDidLoad {
    	[super viewDidLoad];
    	//以下两个方法在开发中是常常会用到的
    //    NSLog(@"%s",__func__);
    //    NSLog(@"%@",self.view.subviews); //能打印出全部子视图,和其frame
    	LogFun;
    	LogSubviews(self.view);
    
    
    	//删除现有的tabBar
    	CGRect rect = self.tabBar.frame;
    	[self.tabBar removeFromSuperview];  //移除TabBarController自带的下部的条
    
    	//測试加入自己的视图
    	UIView *myView = [[UIView alloc] init];
    	myView.frame = rect;
    	myView.backgroundColor = [UIColor redColor];
    	[self.view addSubview:myView];
    
    	for (int i = 0; i < 5; i++) {
    		//UIButton *btn = [[UIButton alloc] init];
            XNTabBarButton *btn = [[XNTabBarButton alloc] init];
            
    		NSString *imageName = [NSString stringWithFormat:@"TabBar%d", i + 1];
    		NSString *imageNameSel = [NSString stringWithFormat:@"TabBar%dSel", i + 1];
    
    		[btn setImage:[UIImage imageNamed:imageName] forState:UIControlStateNormal];
    		[btn setImage:[UIImage imageNamed:imageNameSel] forState:UIControlStateSelected];
    
    		CGFloat x = i * myView.frame.size.width / 5;
    		btn.frame = CGRectMake(x, 0, myView.frame.size.width / 5, myView.frame.size.height);
    
    		[myView addSubview:btn];
            
            btn.tag = i;//设置button的标记, 方便来索引当前的button,并跳转到对应的视图
    
    		//带參数的监听方法记得加"冒号"
    		[btn addTarget:self action:@selector(clickBtn:) forControlEvents:UIControlEventTouchUpInside];
    
    		//设置刚进入时,第一个button为选中状态
    		if (0 == i) {
    			btn.selected = YES;
    			self.selectedBtn = btn;  //设置该button为选中的button
    		}
    	}
    }
    
    /**
     *  自己定义TabBar的button点击事件
     */
    - (void)clickBtn:(UIButton *)button {
    	//1.先将之前选中的button设置为未选中
    	self.selectedBtn.selected = NO;
    	//2.再将当前button设置为选中
    	button.selected = YES;
    	//3.最后把当前button赋值为之前选中的button
    	self.selectedBtn = button;
        
        //4.跳转到对应的视图控制器. (通过selectIndex參数来设置选中了那个控制器)
        self.selectedIndex = button.tag;
    }
    
    @end
    

    XNTabBarButton.h

    #import <UIKit/UIKit.h>
    
    @interface XNTabBarButton : UIButton
    
    @end

    XNTabBarButton.m

    #import "XNTabBarButton.h"
    
    @implementation XNTabBarButton
    /**什么也不做就能够取消系统button的高亮状态*/
    - (void)setHighlighted:(BOOL)highlighted{
    //    [super setHighlighted:highlighted];
    }
    
    @end
    

    五、代码重构

    重构的目的是把代码放到他最该到的地方去. 提高可读写与可拓展性。

    对控件的重构要保证可重用性. 做到封装做其它应用时,能够直接拿过去用的地步.

    tips :
    1、关于initinitWithFrame:
    在对象初始化调用init,会调用initWithFrame方法.
    InitinitWithFrame都会被调用.
    建议自己定义控件不要重init方法,须要初始化重写initWithFrame方法.
    优点:其它人调用不管是调用init,还是调用initWithFrame都会调用initWithFrame方法.

    2、关于控件的布局代码:
    建议写在layoutSubviews方法中.
    不要忘记写super方法
    将设置x,y,frame等写在这里面.
    3、自己定义的Tabbar加入为系统TabBar的子视图,这样TabBar的切换自己主动隐藏/滑动功能就不用自己做了. (hidebottombaronpush)

    重构后的代码例如以下
    将自己定义的TabBar单独建立。并将代码移过去。
    设置代理方法,工具栏button被选中,记录从哪里跳转到哪里. 

    XNTabBar.h

    #import <UIKit/UIKit.h>
    @class XNTabBar;
    
    @protocol XNTabBarDelegate <NSObject>
    /**
     *  工具栏button被选中, 记录从哪里跳转到哪里. (方便以后做对应特效)
     */
    - (void) tabBar:(XNTabBar *)tabBar selectedFrom:(NSInteger) from to:(NSInteger)to;
    
    @end
    
    @interface XNTabBar : UIView
    @property(nonatomic,weak) id<XNTabBarDelegate> delegate;
    /**
     *  使用特定图片来创建button, 这样做的优点就是可扩展性. 拿到别的项目里面去也能换图片直接用
     *
     *  @param image         普通状态下的图片
     *  @param selectedImage 选中状态下的图片
     */
    -(void)addButtonWithImage:(UIImage *)image selectedImage:(UIImage *) selectedImage;
    @end
    


    XNTabBar.m


    //
    //  XNTabBar.m
    //
    //  Created by neng on 14-6-19.
    //  Copyright (c) 2014年 neng. All rights reserved.
    //
    
    #import "XNTabBar.h"
    #import "XNTabBarButton.h"
    
    @interface XNTabBar ()
    /**
     *  设置之前选中的button
     */
    @property (nonatomic, weak) UIButton *selectedBtn;
    @end
    
    @implementation XNTabBar
    
    /**
     *  在这种方法里写控件初始化的东西, 调用init方法时会调用
     */
    //- (id)initWithFrame:(CGRect)frame {
    //	if (self = [super initWithFrame:frame]) {
    //		//加入button
    //		for (int i = 0; i < 5; i++) { //取消掉特定的数字
    //			//UIButton *btn = [[UIButton alloc] init];
    //			XNTabBarButton *btn = [[XNTabBarButton alloc] init];
    //
    //			NSString *imageName = [NSString stringWithFormat:@"TabBar%d", i + 1];
    //			NSString *imageNameSel = [NSString stringWithFormat:@"TabBar%dSel", i + 1];
    //
    //			[btn setImage:[UIImage imageNamed:imageName] forState:UIControlStateNormal];
    //			[btn setImage:[UIImage imageNamed:imageNameSel] forState:UIControlStateSelected];
    //
    //			[self addSubview:btn];
    //
    //			btn.tag = i; //设置button的标记, 方便来索引当前的button,并跳转到对应的视图
    //
    //			//带參数的监听方法记得加"冒号"
    //			[btn addTarget:self action:@selector(clickBtn:) forControlEvents:UIControlEventTouchUpInside];
    //
    //			if (0 == i) {
    //				[self clickBtn:btn];
    //			}
    //		}
    //	}
    //	return self;
    //}
    
    - (void)addButtonWithImage:(UIImage *)image selectedImage:(UIImage *)selectedImage {
    	UIButton *btn = [[UIButton alloc] init];
    
    	[btn setImage:image forState:UIControlStateNormal];
    	[btn setImage:selectedImage forState:UIControlStateSelected];
    
    	[self addSubview:btn];
    
    	//带參数的监听方法记得加"冒号"
    	[btn addTarget:self action:@selector(clickBtn:) forControlEvents:UIControlEventTouchUpInside];
    
    	//假设是第一个button, 则选中(按顺序一个个加入)
    	if (self.subviews.count == 1) {
    		[self clickBtn:btn];
    	}
    }
    
    /**专门用来布局子视图, 别忘了调用super方法*/
    - (void)layoutSubviews {
    	[super layoutSubviews];
    
    	int count = self.subviews.count;
    	for (int i = 0; i < count; i++) {
    		//取得button
    		UIButton *btn = self.subviews[i];
    
    		btn.tag = i; //设置button的标记, 方便来索引当前的button,并跳转到对应的视图
    
    		CGFloat x = i * self.bounds.size.width / count;
    		CGFloat y = 0;
    		CGFloat width = self.bounds.size.width / count;
    		CGFloat height = self.bounds.size.height;
    		btn.frame = CGRectMake(x, y, width, height);
    	}
    }
    
    /**
     *  自己定义TabBar的button点击事件
     */
    - (void)clickBtn:(UIButton *)button {
    	//1.先将之前选中的button设置为未选中
    	self.selectedBtn.selected = NO;
    	//2.再将当前button设置为选中
    	button.selected = YES;
    	//3.最后把当前button赋值为之前选中的button
    	self.selectedBtn = button;
    
    	//却换视图控制器的事情,应该交给controller来做
    	//最好这样写, 先推断该代理方法是否实现
    	if ([self.delegate respondsToSelector:@selector(tabBar:selectedFrom:to:)]) {
    		[self.delegate tabBar:self selectedFrom:self.selectedBtn.tag to:button.tag];
    	}
    
    	//4.跳转到对应的视图控制器. (通过selectIndex參数来设置选中了那个控制器)
    	//self.selectedIndex = button.tag;
    }
    
    @end
    

    原先的XNTabBarController.m经过改动后,凝视了原先的代码。

    //
    //  XNTabBarController.m
    //
    //  Created by neng on 14-6-19.
    //  Copyright (c) 2014年 neng. All rights reserved.
    //
    
    #import "XNTabBarController.h"
    #import "XNTabBarButton.h"
    #import "XNTabBar.h"
    
    @interface XNTabBarController () <XNTabBarDelegate>
    /**
     *  设置之前选中的button
     */
    @property (nonatomic, weak) UIButton *selectedBtn;
    @end
    
    @implementation XNTabBarController
    
    - (void)viewDidLoad {
    	[super viewDidLoad];
    	//以下两个方法在开发中是常常会用到的
    //    NSLog(@"%s",__func__);
    //    NSLog(@"%@",self.view.subviews); //能打印出全部子视图,和其frame
    //	LogFun;
    //	LogSubviews(self.view);
    	//Hell
    
    
    	//删除现有的tabBar
    	CGRect rect = self.tabBar.bounds; //这里要用bounds来加, 否则会加到以下去.看不见
        LogFrame(self.tabBar);
    	//[self.tabBar removeFromSuperview];  //移除TabBarController自带的下部的条
    
    	//測试加入自己的视图
    	XNTabBar *myView = [[XNTabBar alloc] init]; //设置代理必须改掉前面的类型,不能用UIView
    	myView.delegate = self; //设置代理
    	myView.frame = rect;
    	[self.tabBar addSubview:myView]; //加入到系统自带的tabBar上, 这样能够用的的事件方法. 而不必自己去写
        
        //为控制器加入button
        for (int i=0; i<self.viewControllers.count; i++) { //依据有多少个子视图控制器来进行加入button
            
            NSString *imageName = [NSString stringWithFormat:@"TabBar%d", i + 1];
            NSString *imageNameSel = [NSString stringWithFormat:@"TabBar%dSel", i + 1];
            
            UIImage *image = [UIImage imageNamed:imageName];
            UIImage *imageSel = [UIImage imageNamed:imageNameSel];
            
            [myView addButtonWithImage:image selectedImage:imageSel];
        }
        
    
    //    //加入button
    //	for (int i = 0; i < 5; i++) {
    //		//UIButton *btn = [[UIButton alloc] init];
    //        XNTabBarButton *btn = [[XNTabBarButton alloc] init];
    //
    //		NSString *imageName = [NSString stringWithFormat:@"TabBar%d", i + 1];
    //		NSString *imageNameSel = [NSString stringWithFormat:@"TabBar%dSel", i + 1];
    //
    //		[btn setImage:[UIImage imageNamed:imageName] forState:UIControlStateNormal];
    //		[btn setImage:[UIImage imageNamed:imageNameSel] forState:UIControlStateSelected];
    //
    //		CGFloat x = i * myView.frame.size.width / 5;
    //		btn.frame = CGRectMake(x, 0, myView.frame.size.width / 5, myView.frame.size.height);
    //
    //		[myView addSubview:btn];
    //
    //        btn.tag = i;//设置button的标记, 方便来索引当前的button,并跳转到对应的视图
    //
    //		//带參数的监听方法记得加"冒号"
    //		[btn addTarget:self action:@selector(clickBtn:) forControlEvents:UIControlEventTouchUpInside];
    //
    //		//设置刚进入时,第一个button为选中状态
    //		if (0 == i) {
    //			btn.selected = YES;
    //			self.selectedBtn = btn;  //设置该button为选中的button
    //		}
    //	}
    }
    
    /**永远别忘记设置代理*/
    - (void)tabBar:(XNTabBar *)tabBar selectedFrom:(NSInteger)from to:(NSInteger)to {
    	self.selectedIndex = to;
    }
    
    /**
     *  自己定义TabBar的button点击事件
     */
    //- (void)clickBtn:(UIButton *)button {
    //	//1.先将之前选中的button设置为未选中
    //	self.selectedBtn.selected = NO;
    //	//2.再将当前button设置为选中
    //	button.selected = YES;
    //	//3.最后把当前button赋值为之前选中的button
    //	self.selectedBtn = button;
    //
    //    //4.跳转到对应的视图控制器. (通过selectIndex參数来设置选中了那个控制器)
    //    self.selectedIndex = button.tag;
    //}
    
    @end
    

    自己定义后的效果图:




    样例源代码下载 http://download.csdn.net/detail/xn4545945/7572263

    转载请注明出处:http://blog.csdn.net/xn4545945  



  • 相关阅读:
    vb做界面调用c编写的dll
    小记管线冲洗(现场学习)
    管网建模基础
    编写成绩信息管理系统
    MJRefresh超详细讲解
    iOS 在xib或者storyboard中添加AutoLayout后,在代码中修改AutoLayout约束条件
    tableViewCell重用导致图片错乱问题
    更新ruby
    控件基本动画
    Block动画和spring动画
  • 原文地址:https://www.cnblogs.com/gcczhongduan/p/5080574.html
Copyright © 2011-2022 走看看