『微信+朋友圈』是现在常见应用社交模式的标准配置,很多应用会选择像新浪微博一样在底部提供一个标签,能够方便快捷的发布状态,那么今天我们来学习如何快速实现这个功能。
网上的复杂方案
在网上找到的大部分解决方案是这样的
- 创建一个标签栏
- 给标签栏设置五个ChildViewController。
- 创建一个自定义的Button,大小和一个TabbarItem大小一致
- 调用
self.View addsubView:
方法Button放到第三个TabbarItem的位置遮住它,然后给Button添加事件实现效果。
这样做确实能实现这个功能,但是但我们需要调用pop
和push
方法的时候,这个Button的隐藏和展示就成了麻烦事,特别是当你使用StroyBoard中的导航栏时,每次pop
和push
都会有一个动画效果,这个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
类型的参数,这是一个枚举类型,字面意思为图片渲染模式,它的枚举值如下
可以看到,有三个模式,分别为自动,始终原样不动以及始终按照模板渲染,默认是自动。
那么什么是按照模板渲染呢?
这就说到了标签栏处理图片的方式,对于任意一张加载
UITabBarItem
上的图片,在未选中下是灰色的,无论你使用什么颜色的图片,选中状态下是蓝色的,无论你使用什么颜色的图片。这就是所谓按照模板渲染,标签栏给每一张图片都照着这个过程去渲染,通过改变tintColor
就可以改变选中状态下的颜色。而且在默认状态下,如果没有设置selectedImage
,那么选中时的图片会使用UITabBarItem
的image
所使用的图片。
因此,设置一个标签栏只需要设置它每个TabbarItem
的Title``image
,然后设置TabBar
的tintColor
即可。因为即使你在设置选中图片颜色的时候设定参数UIImageRenderingModeAlwaysOriginal
,你不还有一个文字颜色要改嘛?还是得设置tintColor
的值
那么这个image
属性和selectedImage
属性还有用吗?
答案是,有用。
记得天猫美团支付宝这些APP每到逢年过节做的那些花里胡哨的界面吗?假设你的标签栏上是四只猴子,未选中就蹲着,选中就站起来,而且猴子的颜色很丰富,这个时候你就会用到image
和selectImage
,而且记得要把加工模式设置为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:
去执行。
运行看效果
结束
到此为止,我们已经完成了新浪微博标签栏的制作,至于要往这个半透明的发布页面加什么功能,就凭大家发挥了。