自定义UITabBarController
可以在ViewDidLoad里设置子控制器。当然其他地方也是可以的,但是放在这里可以更加有条理。
初始化
- (void)viewDidLoad
{
[super viewDidLoad];
// 添加所有的子控制器
[self addAllChildVcs];
// 创建自定义tabbar
[self addCustomTabBar];
}
设置导航和tab标题
childVc.tabBarItem.title = title; // tabbar标签上标签
childVc.navigationItem.title = title; // 导航栏上标签
定义选中和普通状态下的图片
childVc.tabBarItem.image = [UIImage imageWithName:imageName];
// 声明这张图片用原图(不要渲染)
selectedImage = [selectedImage imageWithRenderingMode:UIImageRenderingModeAlwaysOriginal];
childVc.tabBarItem.selectedImage = selectedImage;
设置选中和普通状态下的字体
// 设置tabBarItem的普通文字颜色
NSMutableDictionary *textAttrs = [NSMutableDictionary dictionary];
textAttrs[UITextAttributeTextColor] = [UIColor blackColor];
textAttrs[UITextAttributeFont] = [UIFont systemFontOfSize:10];
[childVc.tabBarItem setTitleTextAttributes:textAttrs forState:UIControlStateNormal];
// 设置tabBarItem的选中文字颜色
NSMutableDictionary *selectedTextAttrs = [NSMutableDictionary dictionary];
selectedTextAttrs[UITextAttributeTextColor] = [UIColor orangeColor];
[childVc.tabBarItem setTitleTextAttributes:selectedTextAttrs forState:UIControlStateSelected];
自定义UITabbar
自定义一个TabBar继承自UITabBar,然后在layoutSubviews里面设置子控件的frame
初始化设置可以放在initWithFrame中进行
设置选中tabBarItem 的tab bar上渲染的颜色(此图片奖显示在TabBarItem后面)
self.selectionIndicatorImage = [UIImage imageWithName:@"navigationbar_back_highlighted"];
设置背景颜色
self.backgroundImage = [UIImage imageWithName:@"tabbar_background"]
需要自定义布局tabbar时,可以改写
/**
* 布局子控件
*/
- (void)layoutSubviews
{
}
上面的UITabBar是自定义的,加上了一个UIButton
#import "HMTabBar.h"
@interface HMTabBar()
@property (nonatomic, weak) UIButton *plusButton;
@end
@implementation HMTabBar
- (id)initWithFrame:(CGRect)frame
{
self = [super initWithFrame:frame];
if (self) {
if (!iOS7) {
self.backgroundImage = [UIImage imageWithName:@"tabbar_background"];
}
self.selectionIndicatorImage = [UIImage imageWithName:@"navigationbar_button_background"];
// 添加加号按钮
[self setupPlusButton];
}
return self;
}
/**
* 添加加号按钮
*/
- (void)setupPlusButton
{
UIButton *plusButton = [[UIButton alloc] init];
// 设置背景
[plusButton setBackgroundImage:[UIImage imageWithName:@"tabbar_compose_button"] forState:UIControlStateNormal];
[plusButton setBackgroundImage:[UIImage imageWithName:@"tabbar_compose_button_highlighted"] forState:UIControlStateHighlighted];
// 设置图标
[plusButton setImage:[UIImage imageWithName:@"tabbar_compose_icon_add"] forState:UIControlStateNormal];
[plusButton setImage:[UIImage imageWithName:@"tabbar_compose_icon_add_highlighted"] forState:UIControlStateHighlighted];
[plusButton addTarget:self action:@selector(plusClick) forControlEvents:UIControlEventTouchUpInside];
// 添加
[self addSubview:plusButton];
self.plusButton = plusButton;
}
- (void)plusClick
{
HMLog(@"plusClick----");
// 通知代理
if ([self.delegate respondsToSelector:@selector(tabBarDidClickedPlusButton:)]) {
[self.delegate tabBarDidClickedPlusButton:self];
}
}
/**
* 布局子控件
*/
- (void)layoutSubviews
{
[super layoutSubviews];
// 设置plusButton的frame
[self setupPlusButtonFrame];
// 设置所有tabbarButton的frame
[self setupAllTabBarButtonsFrame];
}
/**
* 设置所有plusButton的frame
*/
- (void)setupPlusButtonFrame
{
self.plusButton.size = self.plusButton.currentBackgroundImage.size;
self.plusButton.center = CGPointMake(self.width * 0.5, self.height * 0.5);
}
/**
* 设置所有tabbarButton的frame
*/
- (void)setupAllTabBarButtonsFrame
{
int index = 0;
// 遍历所有的button
for (UIView *tabBarButton in self.subviews) {
// 如果不是UITabBarButton, 直接跳过
if (![tabBarButton isKindOfClass:NSClassFromString(@"UITabBarButton")]) continue;
// 根据索引调整位置
[self setupTabBarButtonFrame:tabBarButton atIndex:index];
// 索引增加
index++;
}
}
/**
* 设置某个按钮的frame
*
* @param tabBarButton 需要设置的按钮
* @param index 按钮所在的索引
*/
- (void)setupTabBarButtonFrame:(UIView *)tabBarButton atIndex:(int)index
{
// 计算button的尺寸
CGFloat buttonW = self.width / (self.items.count + 1);
CGFloat buttonH = self.height;
tabBarButton.width = buttonW;
tabBarButton.height = buttonH;
if (index >= 2) {
tabBarButton.x = buttonW * (index + 1);
} else {
tabBarButton.x = buttonW * index;
}
tabBarButton.y = 0;
}
@end
设置TabBarItem
/**
* 添加一个子控制器
*
* @param childVc 子控制器对象
* @param title 标题
* @param imageName 图标
* @param selectedImageName 选中的图标
*/
- (void)addOneChlildVc:(UIViewController *)childVc title:(NSString *)title imageName:(NSString *)imageName selectedImageName:(NSString *)selectedImageName
{
// 设置标题
childVc.title = title;
// 设置图标
childVc.tabBarItem.image = [UIImage imageWithName:imageName];
// 设置tabBarItem的普通文字颜色
NSMutableDictionary *textAttrs = [NSMutableDictionary dictionary];
textAttrs[UITextAttributeTextColor] = [UIColor blackColor];
textAttrs[UITextAttributeFont] = [UIFont systemFontOfSize:10];
[childVc.tabBarItem setTitleTextAttributes:textAttrs forState:UIControlStateNormal];
// 设置tabBarItem的选中文字颜色
NSMutableDictionary *selectedTextAttrs = [NSMutableDictionary dictionary];
selectedTextAttrs[UITextAttributeTextColor] = [UIColor orangeColor];
[childVc.tabBarItem setTitleTextAttributes:selectedTextAttrs forState:UIControlStateSelected];
// 设置选中的图标
UIImage *selectedImage = [UIImage imageWithName:selectedImageName];
if (iOS7) {
// 声明这张图片用原图(别渲染)
selectedImage = [selectedImage imageWithRenderingMode:UIImageRenderingModeAlwaysOriginal];
}
childVc.tabBarItem.selectedImage = selectedImage;
// 添加为tabbar控制器的子控制器
HMNavigationController *nav = [[HMNavigationController alloc] initWithRootViewController:childVc];
[self addChildViewController:nav];
}
需要重新调整子控件的布局时,调用setNeedsLayout方法,此方法会自动调用setFrame方法
[self.tabBar setNeedsLayout];
自定义UINavigationController
设置主题
/**
* 当第一次使用这个类的时候调用1次
*/
+ (void)initialize
{
// 设置UINavigationBarTheme的主
[self setupNavigationBarTheme];
// 设置UIBarButtonItem的主题
[self setupBarButtonItemTheme];
}
通过设置+ (instancetype)appearance;做统一的设置
设置UINavigationBar的主题
/**
* 设置UINavigationBarTheme的主题
*/
+ (void)setupNavigationBarTheme
{
UINavigationBar *appearance = [UINavigationBar appearance];
// 设置导航栏背景
if (!iOS7) {
[appearance setBackgroundImage:[UIImage imageWithName:@"navigationbar_background"] forBarMetrics:UIBarMetricsDefault];
}
// 设置文字属性
NSMutableDictionary *textAttrs = [NSMutableDictionary dictionary];
textAttrs[UITextAttributeTextColor] = [UIColor blackColor];
textAttrs[UITextAttributeFont] = [UIFont boldSystemFontOfSize:20];
// UIOffsetZero是结构体, 只要包装成NSValue对象, 才能放进字典\数组中,去除阴影效果
textAttrs[UITextAttributeTextShadowOffset] = [NSValue valueWithUIOffset:UIOffsetZero];
[appearance setTitleTextAttributes:textAttrs];
}
设置UIBarButtonItem的主题
/**
* 设置UIBarButtonItem的主题
*/
+ (void)setupBarButtonItemTheme
{
// 通过appearance对象能修改整个项目中所有UIBarButtonItem的样式
UIBarButtonItem *appearance = [UIBarButtonItem appearance];
/**设置文字属性**/
// 设置普通状态的文字属性
NSMutableDictionary *textAttrs = [NSMutableDictionary dictionary];
textAttrs[UITextAttributeTextColor] = [UIColor orangeColor];
textAttrs[UITextAttributeFont] = [UIFont systemFontOfSize:15];
textAttrs[UITextAttributeTextShadowOffset] = [NSValue valueWithUIOffset:UIOffsetZero];
[appearance setTitleTextAttributes:textAttrs forState:UIControlStateNormal];
// 设置高亮状态的文字属性
NSMutableDictionary *highTextAttrs = [NSMutableDictionary dictionaryWithDictionary:textAttrs];
highTextAttrs[UITextAttributeTextColor] = [UIColor redColor];
[appearance setTitleTextAttributes:highTextAttrs forState:UIControlStateHighlighted];
// 设置不可用状态(disable)的文字属性
NSMutableDictionary *disableTextAttrs = [NSMutableDictionary dictionaryWithDictionary:textAttrs];
disableTextAttrs[UITextAttributeTextColor] = [UIColor lightGrayColor];
[appearance setTitleTextAttributes:disableTextAttrs forState:UIControlStateDisabled];
/**设置背景**/
// 技巧: 为了让某个按钮的背景消失, 可以设置一张完全透明的背景图片
[appearance setBackgroundImage:[UIImage imageWithName:@"navigationbar_button_background"] forState:UIControlStateNormal barMetrics:UIBarMetricsDefault];
}
如果需要更改后续UIBarButtonItem的样式只要重新自定义其属性就可以
统一处理所有和导航有关的push事件
在自定义UINavigationController中重写-(void)pushViewController:(UIViewController *)viewController animated:(BOOL)animate;方法
/**
* 能拦截所有push进来的子控制器
*/
- (void)pushViewController:(UIViewController *)viewController animated:(BOOL)animated
{
if (self.viewControllers.count > 0) { // 如果现在push的不是栈底控制器(最先push进来的那个控制器)
viewController.hidesBottomBarWhenPushed = YES;
// 设置导航栏按钮
viewController.navigationItem.leftBarButtonItem = [UIBarButtonItem itemWithImageName:@"navigationbar_back" highImageName:@"navigationbar_back_highlighted" target:self action:@selector(back)];
viewController.navigationItem.rightBarButtonItem = [UIBarButtonItem itemWithImageName:@"navigationbar_more" highImageName:@"navigationbar_more_highlighted" target:self action:@selector(more)];
}
[super pushViewController:viewController animated:animated];
}
一种调整Tabbar外观的思路
UITabBar的样式和预期的不同,首先在viewDidLoad方法中输出self.view.subViews
-(void)viewDidAppear:(BOOL)animated{
[super viewDidAppear:animated];
NSLog(@"%@",self.tabBar.subViews);
}
输出结果
(
"<_UITabBarBackgroundView: 0x7fc021df6590; frame = (0 0; 375 49); autoresize = W; userInteractionEnabled = NO; layer = <CALayer: 0x7fc02400a060>>",
"<UITabBarButton: 0x7fc021ddcaa0; frame = (2 1; 90 48); opaque = NO; layer = <CALayer: 0x7fc021e084e0>>",
"<UITabBarButton: 0x7fc021de4230; frame = (96 1; 90 48); opaque = NO; layer = <CALayer: 0x7fc021de4b40>>",
"<UITabBarButton: 0x7fc021deb780; frame = (190 1; 89 48); opaque = NO; layer = <CALayer: 0x7fc021e06340>>",
"<UITabBarButton: 0x7fc021e0ef50; frame = (283 1; 90 48); opaque = NO; layer = <CALayer: 0x7fc021de5f90>>",
"<UIImageView: 0x7fc02400b8f0; frame = (0 -0.5; 375 0.5); autoresize = W; userInteractionEnabled = NO; layer = <CALayer: 0x7fc02400b520>>"
)
但是UITabBarButton并不是公开的,所以查看其父类,是UIControl
继续遍历其subview,找到一个select有关的view将其从super中移除。可以用这个方法做一定的遍历,调整特定属性
-(void)viewDidAppear:(BOOL)animated{
[super viewDidAppear:animated];
for (UIView *child in self.tabBar.subviews) {
NSLog(@"%@",child.superclass);
NSLog(@"%@",child.subviews);
for (UIView * childchild in child.subviews) {
if([childchild isKindOfClass:[UILabel class]]){
UILabel *label=(UILabel *)childchild;
label.font=[UIFont systemFontOfSize:15];
}
}
}
NSLog(@"%@",self.tabBar.subviews);
}
runtime机制
KVC修改readonly的属性
[self setValue:customTabBar forKeyPath:@"tabBar"];
NSLog(@"%p",customTabBar);
右滑返回手势
在系统的导航控制器基类中设置
UIGestureRecognizerDelegate 声明代理
self.interactivePopGestureRecognizer.delegate = self;
// 作用:拦截手势触发
- (BOOL)gestureRecognizerShouldBegin:(UIGestureRecognizer *)gestureRecognizer{
// 注意:只有非根控制器才有滑动返回功能,根控制器没有。
// 判断导航控制器是否只有一个子控制器,如果只有一个子控制器,肯定是根控制器
if(self.viewControllers.count == 1){
// 表示用户在根控制器界面,就不需要触发滑动手势,
return NO;
}
return YES;
}
参考资料
http://blog.csdn.net/u011452278/article/details/51535506