重新认识UITabBarController,做出新浪微博标签栏

『微信+朋友圈』是现在常见应用社交模式的标准配置,很多应用会选择像新浪微博一样在底部提供一个标签,能够方便快捷的发布状态,那么今天我们来学习如何快速实现这个功能。

新浪微博截图
新浪微博截图

网上的复杂方案

在网上找到的大部分解决方案是这样的

  1. 创建一个标签栏
  2. 给标签栏设置五个ChildViewController。
  3. 创建一个自定义的Button,大小和一个TabbarItem大小一致
  4. 调用 self.View addsubView:方法Button放到第三个TabbarItem的位置遮住它,然后给Button添加事件实现效果。

这样做确实能实现这个功能,但是但我们需要调用poppush方法的时候,这个Button的隐藏和展示就成了麻烦事,特别是当你使用StroyBoard中的导航栏时,每次poppush都会有一个动画效果,这个Button会尤其不协调。当然,你可以通过不断修改逻辑和代码去实现,但是这里给大家介绍一种更简单的方法。


开始前的准备

首先准备一些标签栏用的图标,手边没有素材的可以去[阿里巴巴矢量图]下载一些使用

准备图片

然后创建一个新项目并把图片导入进去

创建项目并导入图片

创建一个继承于UITabbarController的标签栏并作为根视图控制器

创建导航栏

给标签栏添加视图控制器

先给MyTabbarController添加以下方法

- (void)addViewControllerWithTitle:(NSString *)title image:(NSString *)image 
{
UIViewController * vc = [[UIViewController alloc]init];
vc.view.backgroundColor = [UIColor whiteColor];
UINavigationController * nav = [[UINavigationController alloc]initWithRootViewController:vc];
[self addChildViewController:nav];
nav.title = title;
nav.tabBarItem.image = [UIImage imageNamed:image];
}

在ViewDidLoad中调用这个方法

- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view.
self.tabBar.tintColor = ColorFromRGB(0xEA8010);
[self addViewControllerWithTitle:@"首页" image:@"tab_index"];
[self addViewControllerWithTitle:@"消息" image:@"tab_message"];

UIViewController * vc = [UIViewController new];
[self addChildViewController:vc];
vc.tabBarItem.image = [[UIImage imageNamed:@"tab_release"]imageWithRenderingMode:UIImageRenderingModeAlwaysOriginal];
vc.tabBarItem.imageInsets = UIEdgeInsetsMake(5, 0, -5, 0);

[self addViewControllerWithTitle:@"发现" image:@"tab_discover"];
[self addViewControllerWithTitle:@"我的" image:@"tab_mine"];

}

哦对了,你还需要这个宏来将一个十六进制的颜色转化成UIColor对象

#define ColorFromRGB(rgbValue) [UIColor colorWithRed:((float)((rgbValue & 0xFF0000) >> 16))/255.0 green:((float)((rgbValue & 0xFF00) >> 8))/255.0 blue:((float)(rgbValue & 0xFF))/255.0 alpha:1.0]

运行看看效果

运行效果
使用标签栏的误区

我们都知道每一个UITabBarItem都有一个image属性和selectedImage属性,分别对应未选中状态下的图片和选中状态下的图片。
我们还知道UITabBar有一个属性叫做tintColor,表示当某个TabBarItem处于高亮状态下时的颜色。
那么他们究竟有什么区别呢?
我们先从上面代码中那句
[[UIImage imageNamed:@"tab_release"]imageWithRenderingMode:UIImageRenderingModeAlwaysOriginal]说起
这个RenderingMode的参数需要一个UIImageRenderingMode类型的参数,这是一个枚举类型,字面意思为图片渲染模式,它的枚举值如下

UIImageRenderingMode

可以看到,有三个模式,分别为自动,始终原样不动以及始终按照模板渲染,默认是自动。
那么什么是按照模板渲染呢?
这就说到了标签栏处理图片的方式,对于任意一张加载UITabBarItem上的图片,在未选中下是灰色的,无论你使用什么颜色的图片,选中状态下是蓝色的,无论你使用什么颜色的图片。这就是所谓按照模板渲染,标签栏给每一张图片都照着这个过程去渲染,通过改变tintColor就可以改变选中状态下的颜色。而且在默认状态下,如果没有设置selectedImage,那么选中时的图片会使用UITabBarItemimage所使用的图片。

因此,设置一个标签栏只需要设置它每个TabbarItemTitle``image,然后设置TabBartintColor即可。因为即使你在设置选中图片颜色的时候设定参数UIImageRenderingModeAlwaysOriginal,你不还有一个文字颜色要改嘛?还是得设置tintColor的值

那么这个image属性和selectedImage属性还有用吗?
答案是,有用。
记得天猫美团支付宝这些APP每到逢年过节做的那些花里胡哨的界面吗?假设你的标签栏上是四只猴子,未选中就蹲着,选中就站起来,而且猴子的颜色很丰富,这个时候你就会用到imageselectImage,而且记得要把加工模式设置为UIImageRenderingModeAlwaysOriginal

SO,如果你的项目只是一个传统的标签栏,那么问美工要切图的时候就可以跟他说,"你就搞个形状给我就行了,颜色劳资自己搞定╭(′▽`)╯"

回到我们的程序,中间的TabBarItem我们就将其图片的渲染模式设置为UIImageRenderingModeAlwaysOriginal,这样它即使在未选中状态下,依然会是橘黄色。我们不给它加标题,并且调整一下它的位置,这样就有了中间的按钮。

创建发布消息页面

我们首先创建一个发布消息的UIView

创建发布消息的界面

Release.h中这么写
@interface ReleaseView : UIView
@property(nonatomic,strong)UIVisualEffectView * effectView;
@end

Release.m中这样写
- (instancetype)initWithFrame:(CGRect)frame
{
if (self = [super initWithFrame:frame]) {
UIBlurEffect * effrct = [UIBlurEffect effectWithStyle:UIBlurEffectStyleLight];
_effectView = [[UIVisualEffectView alloc]initWithEffect:effrct];
_effectView.frame = self.bounds;
[self addSubview:_effectView];

    UIButton * cancelBtn = [UIButton buttonWithType:UIButtonTypeCustom];
    cancelBtn.frame = CGRectMake(self.bounds.size.width / 5 * 2, self.bounds.size.height - 49 , 40, 40);
    
    cancelBtn.center = CGPointMake(self.bounds.size.width / 2, self.bounds.size.height - 49);
    [self addSubview:cancelBtn];
    [cancelBtn setBackgroundImage:[UIImage imageNamed:@"release_cancel"] forState:UIControlStateNormal];
    
    [cancelBtn addTarget:self action:@selector(cancelBtnClicked:) forControlEvents:UIControlEventTouchUpInside];
}
return self;
}
- (void)cancelBtnClicked:(UIButton *)btn
{
self.hidden = YES;
}
- (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event
{
self.hidden = YES;
}

UIVisualEffectView是iOS 8.0之后提供的一种用来快速实现半透明效果的视图,通过如上所示的三行代码就可以轻松创建一个半透明的蒙版,它提供三种风格,分别是Light,ExLight和Dark,具体效果大家可以自己试验。

实现最终效果

回到我们的标签栏,将刚才创建的ReleaseView头文件引入
#import "ReleaseView.h"
添加为成员属性
@property(nonatomic,strong)ReleaseView * releaseView;

ViewDidLoad中添加代码

- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view.

....
_releaseView = [[ReleaseView alloc]initWithFrame:self.view.bounds];
_releaseView.hidden = YES;
[self.view addSubview:_releaseView];
....
}

接下来是另一个很重要的步骤,重写setSelectedViewController:(__kindof UIViewController *)selectedViewController方法
- (void)setSelectedViewController:(__kindof UIViewController *)selectedViewController
{
if ([selectedViewController class] == [UIViewController class]) {
_releaseView.hidden = NO;
}
else
{
[super setSelectedViewController:selectedViewController];
}
}

这里我们给其他TabBarItem对应的都是一个导航栏控制器,只有中间这个是个普通的视图控制器,因此可以这么作比较,实际项目中每个标签对应的一定是不一样的视图控制器,因此根据实际情况写即可。

为什么是setSelectedViewController: 不是setSelectedIndex:

有些同学可能注意到了,标签栏有setSelectedViewController:setSelectedIndex:两个方法。那么为什么重写的是前一个呢?
因为当我们主动点击某个标签时调用的就是前一个方法。
那么后一个方法什么时候调用呢?
后一个方法其实是留给开发者使用的一个接口,用来自动跳转到某个标签栏。比如我们可以在调用[self setSelectedIndex:1];让APP一开始就显示第三个标签栏。而这个方法内部其实还是调用了setSelectedViewController:去执行。

运行看效果
运行效果

结束

到此为止,我们已经完成了新浪微博标签栏的制作,至于要往这个半透明的发布页面加什么功能,就凭大家发挥了。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 205,132评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 87,802评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 151,566评论 0 338
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,858评论 1 277
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,867评论 5 368
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,695评论 1 282
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,064评论 3 399
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,705评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 42,915评论 1 300
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,677评论 2 323
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,796评论 1 333
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,432评论 4 322
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,041评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,992评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,223评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,185评论 2 352
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,535评论 2 343

推荐阅读更多精彩内容