一、自己定义的思路

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

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

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

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

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

三、细节非常重要

1. 让自己创建的button关联到viewController:
•用tabbar的selectedIndex属性.设置这个属性即可了.
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、关于init与initWithFrame:
•在对象初始化调用init时,会调用initWithFrame方法.
•Init与initWithFrame都会被调用.
•建议自己定义控件不要重写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

自己定义后的效果图:

watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQveG40NTQ1OTQ1/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast" alt="">

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

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

【iOS】自己定义TabBarController的更多相关文章

  1. ios宏定义字符串

    ios宏定义字符串 #define objcString(str) @""#str"" 使用效果: objcString(字符串)

  2. iOS宏定义的使用与规范

    宏定义在很多方面都会使用,例如定义高度.判断iOS系统.工具类,还有诸如文件路径.服务端api接口文档.为了对宏能够快速定位和了解其功能,我们最好在定义的时候将其放入特定的头文件中 定义尺寸类的宏 D ...

  3. ios 宏定义 系统版本 判定

    当需要判断iOS系统版本的时候,相信很多人都会这么干: #define SystemVersion [[UIDevice currentDevice] systemVersion].floatValu ...

  4. iOS宏定义

    1.__OBJC__宏定义作用 在.pch 文件中一般都会自动加上这句宏定义,表示宏内引用的文件确保只被使用Objective-C语言的文件所引用,保证引用关系的清晰.因为在一个OC工程中,可能包含. ...

  5. 高效的iOS宏定义

    iOS开发过程中使用一些常用的宏可以提高开发效率,提高代码的重用性:将这些宏放到一个头文件里然后再放到工程中的-Prefix.pch文件中(或者直接放到-Prefix.pch中)直接可以使用,灰常方便 ...

  6. 转 iOS宏定义的使用与规范

    宏定义在很多方面都会使用,例如定义高度.判断iOS系统.工具类,还有诸如文件路径.服务端api接口文档.为了对宏能够快速定位和了解其功能,我们最好在定义的时候将其放入特定的头文件中,下面我抛砖引玉,对 ...

  7. ios宏定义学习

    宏简介: 宏是一种批量处理的称谓.一般说来,宏是一种规则或模式,或称语法替换 ,用于说明某一特定输入(通常是字符串)如何根据预定义的规则转换成对应的输出(通常也是字符串).这种替换在预编译时进行,称作 ...

  8. iOS 自己定义页面的切换动画与交互动画 By Swift

    在iOS7之前,开发人员为了寻求自己定义Navigation Controller的Push/Pop动画,仅仅能受限于子类化一个UINavigationController,或是用自己定义的动画去覆盖 ...

  9. iOS 如何使用TabbarController

    xcode中给我内置很多app模版,不过很多时候我们需要更加灵活的初始化项目.下面我就简单介绍一下,如何从0开始制作一个tabbar app. 创建个项目,由于我们从头开始写程序,因此理论上对模版没有 ...

随机推荐

  1. 关于Django的登录系统

    首先需要明确的是登录的本质:登录就是服务器确认当前用户的身份,并将数据库中的记录提取匹配 默认的登录系统是用户名密码方式,这种方式很平常,也没什么特别的.这里主要说的是第三方验证登录 通常第三方验证登 ...

  2. jmeter分布式测试的坑(转)

    本文转自:https://www.cnblogs.com/lsjdddddd/p/5806077.html 有关jmeter分布式测试的环境配置,大概就是那样,但是每次想要进行jmeter分布式测试的 ...

  3. BZOJ 1007 HNOI 2008 水平可见直线 计算几何+栈

    题目大意:给出一些笛卡尔系中的一些直线,问从(0,+∞)向下看时能看到哪些直线. 思路:半平面交可做,可是显然用不上. 类似于求凸包的思想,维护一个栈. 先将全部直线依照k值排序.然后挨个压进去,遇到 ...

  4. Java Web学习总结(4)——HttpServletResponse对象入门

    Web服务器收到客户端的http请求,会针对每一次请求,分别创建一个用于代表请求的request对象.和代表响应的response对象. request和response对象即然代表请求和响应,那我们 ...

  5. IOS上架App Store商店步骤

    苹果官方在2015年05-06月开发者中心进行了改版,网上的APP Store上架大部分都不一样了,自己研究总结一下,一个最新的上架教程以备后用. 原文地址:http://www.16css.com/ ...

  6. GO语言学习(一)Windows 平台下 Go 语言的安装和环境变量设置

    1. Go 语言 SDK 安装包下载和安装 GO语言安装包下载地址:https://www.golangtc.com/download 下载 go1.9.2.windows-amd64 2. Go 语 ...

  7. 【Codeforces Round #299 (Div. 2) B】Tavas and SaDDas

    [链接] 我是链接,点我呀:) [题意] 在这里输入题意 [题解] 每次取出最小的数字,在后面加上一个4或一个7就好; 会发现最后的数字很少的. [代码] #include <bits/stdc ...

  8. Linux平台Makefile文件的编写基础篇

    目的:        基本掌握了 make 的用法,能在Linux系统上编程. 环境:        Linux系统,或者有一台Linux服务器,通过终端连接.一句话:有Linux编译环境. 准备: ...

  9. js cookie介绍和实例(用于自动登录,记住用户名等)

    js cookie介绍和实例(用于自动登录,记住用户名等) 一.总结 1.cookie在客户端:因为js是最初是用来在客户端和服务器端进行通信使用的,所以客户端比如js可以操作cookie正常 2.c ...

  10. 【5001】n皇后问题

    Time Limit: 10 second Memory Limit: 2 MB 在n*n的棋盘上放置n个皇后(国际象棋中的皇后,n≤10)而彼此不受攻击(即在棋盘的任一行,任一列和任一对角线上不能放 ...