【iOS】自己定义TabBarController

一、自己定义的思路

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" >

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

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

时间: 2024-08-04 13:07:46

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

iOS enum 定义与使用

枚举其实很重要,特别是在应用开发初期,服务器端数据格式需要更改得情况下,枚举和宏都能是程序简洁,并且改动小. 网上有个人写的言简意赅,适合初学 转自:http://blog.csdn.net/ysy441088327/article/details/8012677 题记: 蛋疼的枚举, 千万别小视了! 进入正题: 首先要知道的是,枚举值 它是一个整形(int) 并且,它不参加内存的占用和释放 枚举定义变量即可直接使用,不用初始化. 枚举的定义如下: typedef enum { //以下是枚举成

【iOS】自定义TabBarController

一.自定义的思路 iOS中的TabBarController确实已经很强大了,大部分主流iOS应用都会采用.但是往往也不能满足全部的需求,因此需要自定义TabBar,自定义需要对系统的TabBar工作方式有很好的理解,自定义需要勇气. 自定义TabBar的原则:尽量利用系统自带TabBar,只改需要改的地方. 二.自定义TabBar的总体过程 1.先把自带的TabBar条给取消了 2.自己做一个view,上面放几个按钮,设定按钮的点击事件.并设置selectIndex. 3.关联各个子viewC

ios 宏定义 系统版本 判定

====================================================== 当需要判断iOS系统版本的时候,相信很多人都会这么干: #define SystemVersion [[UIDevice currentDevice] systemVersion].floatValue 现在告诉屌丝们一个更好的办法就是其实系统已经做了类似的宏定义,不需要我们再去定义了 在Simulator-IOS7.0/usr/include/Availability.h中已经定义了很

iOS宏定义的使用与规范

http://my.oschina.net/leejan97/blog/354904 宏定义在很多方面都会使用,例如定义高度.判断iOS系统.工具类,还有诸如文件路径.服务端api接口文档.为了对宏能够快速定位和了解其功能,我们最好在定义的时候将其放入特定的头文件中,下面我抛砖引玉,对一些常用的宏进行分类.分文件定义,希望对大家有所帮助. 定义尺寸类的宏 DimensMacros.h //状态栏高度 #define STATUS_BAR_HEIGHT 20 //NavBar高度 #define

iOS 如何使用TabbarController

xcode中给我内置很多app模版,不过很多时候我们需要更加灵活的初始化项目.下面我就简单介绍一下,如何从0开始制作一个tabbar app. 创建个项目,由于我们从头开始写程序,因此理论上对模版没有特殊的要求.这里我们选择Single View Application模版. 创建完成后,我们就可以开始写程序了.iOS app程序都是以一个UIWindows为基础的,因此我们只需创建好一个VC然后将windows的rootViewController设置为当前VC即可.下面是代码 ''' -(B

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

在iOS7之前,开发人员为了寻求自己定义Navigation Controller的Push/Pop动画,仅仅能受限于子类化一个UINavigationController,或是用自己定义的动画去覆盖它.可是随着iOS7的到来,Apple针对开发人员推出了新的工具,以更灵活地方式管理UIViewController切换. 我把终于的Demo稍做改动,算是找了一个合适的应用场景,另外配上几张美图,拉拉人气. 尽管是Swift的Demo,可是转成Objective-C相当easy. 终于效果预览:

高效的iOS宏定义

iOS开发过程中使用一些常用的宏可以提高开发效率,提高代码的重用性:将这些宏放到一个头文件里然后再放到工程中的-Prefix.pch文件中(或者直接放到-Prefix.pch中)直接可以使用,灰常方便. 本文整理自http://www.cocoachina.com/applenews/devnews/2013/0328/5907.html . 做了一些分类和注释,可以根据自己习惯再添加或者删除或者修改这些宏进行使用. [cpp] view plaincopy // //  MacroDefini

iOS 项目架构tabbarController 嵌套 navbarController

简单思路: 进入APP,首先加载 splashVC,加载完成之后,在viewDidAppear里跳转到loginVC,(这里一定要在viewDidLoad方法里新建loginVC跳转). 登陆成功之后,进入tabBarController,tabView里有四个模块,每个模块由navController控制器做导航,可以进入各自的子模块.进入二级子模块要隐藏tabbar. 待补充

ios宏定义应该呆在恰当的地方

项目为了看起来整洁 并减少不必要的多次拼写 我们会把这样的方法 做成宏定义 那么问题来了 很多文件同时用到一个或多个宏定义 写完之后就会变成这个样子 看起来很乱 阅读性也不好 那么问题来了怎么解决嘞 我要发功了 把所有的宏定义都写入一个文件 然后那个用到宏定义 直接导入TRMacro就可以了 是不是很吊 虽然很基础 但是很实用