项目总结2 UITabBarController为根视图的基础界面细节处理-返回按钮等

上一篇文章讲了如何搭建以UITabBarController为根视图的界面,虽然是个简单的基础界面,但还是有几个细节问题需要处理。

TabBar中button的selectedImage

不知道大家有没有注意到,在setupChildViewControllers 这个函数中设置了selectedImage,但是没有效果。有些应用,比如微博,TabBar中button选中状态是橘黄色的,而不是系统默认的蓝色。这是怎么做到的呢?下面我就来说一说。
button上显示的图片是被渲染过后再显示的,但我们就不希望系统帮我们渲染图片,所以我们需要设置一下了。UIImage有个方法imageWithRenderingMode: 这个方法就可以设置图片渲染方式。这里我们不需要渲染,传个UIImageRenderingModeAlwaysOriginal 即可。因为这个处理方式可能很多地方都会用到,我们不妨给UIImage写一个分类。

//记得在头文件中声明下面两个方法
#import "UIImage+JHExtension.h"

@implementation UIImage (JHExtension)
//成员方法,通过点操作来访问
- (UIImage *)jh_originalImage
{
    return [self imageWithRenderingMode:UIImageRenderingModeAlwaysOriginal];
}
//静态方法,通过类名访问
+ (UIImage *)jh_OriginalImageWithName:(NSString *)imageName
{
    UIImage *image = [UIImage imageNamed:imageName];
    [image imageWithRenderingMode:UIImageRenderingModeAlwaysOriginal];

    return image;
}

@end

有了这个分类,我们在设置button的时候导入头文件UIImage+JHExtension ,然后我们可以修改上一篇文章中的setupChildViewControllers方法中设置button的selectedImage代码为:

childView.tabBarItem.selectedImage = [UIImage imageNamed:selectedImageName].jh_originalImage;

这样就防止系统渲染图片,从而能显示我们想要显示的图片,而非系统默认的蓝色图片。

UITabBarItem的风格

通常我们都会在创建UITabBarItem的时候顺带设置下风格,比如字体颜色等。但是每次都需要手动写这些代码会有些麻烦,重复代码多,而且如果要更改的话也比较繁琐。这里我介绍一个方法,UITabBarItem有个appearance,这个就是UITabBarItem的皮肤,如果设置了这个appearance,那么所有UITabBarItem的风格都会根据Appearance来设置。如果只需要设置某些view导航栏的风格,可以用appearanceWhenContainedInInstanceOfClass函数,传入包含需要设置的view的数组就行。只要有UI_APPEARANCE_SELECTOR 宏的UIView都有appearance。话不多说,直接上代码:

/**
 *  使用Appearance设置UITabBarItem的风格,这样整个APP中的UITabBarItem都是这个风格
 */
- (void)setUpTabBarItemTitleColor
{
    //用字典存储属性和其对应的值
    NSDictionary *dic = @{
                          NSForegroundColorAttributeName: [UIColor darkGrayColor]
                          };
    //取得appearance对象
    UITabBarItem *item = [UITabBarItem appearance];
    //通过appearance来设置UITabBarItem的属性
    [item setTitleTextAttributes:dic forState:UIControlStateSelected];
}

在合适的地方调用这个方法即可。下面来张图看看效果

项目总结2 UITabBarController为根视图的基础界面细节处理-返回按钮等_第1张图片

返回按钮的设置

先来张图

项目总结2 UITabBarController为根视图的基础界面细节处理-返回按钮等_第2张图片

我在这个第一个UITabBarItem对应的ViewController中响应了一个点击完成事件,点击屏幕后push一个绿色的ViewController,你会发现左上角多了一个蓝色的返回按钮,按钮的文本是push绿色ViewController的ViewController的title,而且点击过后这个返回按钮后按钮变淡了。如果我需要自定义这个返回按钮怎么做呢?如果我想整个应用中的返回按钮都使用我自定义的按钮又怎么办呢?下面我们就来解决这个问题。

  1. 首先我们来看看如何更改一个返回按钮。
    返回按钮是在ViewController被push后系统自动显示出来的按钮,功能是返回到push这个ViewController的ViewController。返回按钮是UIBarButtonItem,而UIBarButtonItem的功能没有UIButton强大,如果要实现更强大的按钮功能,我们可以用UIButton来替换UIBarButtonItem,并且在ViewController被push之前,我们就该设置好。下面我们来实验一下,我在第一个TabBarItem对应的ViewController中添加了一个点击完成事件,点击屏幕后,我创建一个ViewController并设置好返回按钮,然后push该ViewController。
- (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event
{
    //创建ViewController
    UIViewController *vc = [[UIViewController alloc] init];
    vc.view.backgroundColor = [UIColor greenColor];

    //创建一个Button作为返回按钮
    UIButton *backButton = [UIButton buttonWithType:UIButtonTypeCustom];

    //设置返回按钮的文本及其颜色
    [backButton setTitle:@"返回" forState:UIControlStateNormal];
    [backButton setTitleColor:[UIColor blackColor] forState:UIControlStateNormal];
    [backButton setTitleColor:[UIColor redColor] forState:UIControlStateHighlighted];
    //这里的size是我为UIView写的分类,方便直接调用到size
    backButton.size = CGSizeMake(40, 40);
    //添加按钮响应
    [backButton addTarget:self action:@selector(back) forControlEvents:UIControlEventTouchUpInside];

    //如果push完view后需要隐藏底部的工具栏,那么可以打开这句
    //vc.hidesBottomBarWhenPushed = YES;

    //UIBarButtonItem有个initWithCustomView,可以用其它UIView来填充到UIBarbuttonItem中,这样我们就可以把刚才创建的button放在返回按钮所在的位置,替换系统默认的返回按钮
    vc.navigationItem.leftBarButtonItem = [[UIBarButtonItem alloc] initWithCustomView:backButton];

    //push ViewController
    [self.navigationController pushViewController:vc animated:YES];
}

- (void)back
{
    //弹出刚才push的view
    [self.navigationController popViewControllerAnimated:YES];
}

下面是执行效果,我们可以看到返回按钮已经是我们自定义的了。

项目总结2 UITabBarController为根视图的基础界面细节处理-返回按钮等_第3张图片

  • 2 接下来我们看看如何设置所有被Push的View的返回按钮,并像系统提供的那种一样带箭头。

    • 要让自定义的返回按钮带箭头前,我们必须要了解UIButton的构造。UIButton中,有一个ImageView(左)和一个UILabel(右),我们如果同时为一个UIButton设置了image和title,那么image会显示在button的左半部分,title在button的右半部分。这样我们就比较清楚该怎么设置带箭头的返回按钮了,把图片和文字同时设置好即可。

    • 知道了button怎么设置后,我们要想想如何一劳永逸,只用设置一次就可以改变所有的返回按钮。我们是在push之前设置好view的种种属性,然后push的,我们需要找到一个方法,让所有通过push方式切换的ViewController都能使用我们自定义的返回按钮,能让我们来设置被push的view,怎样做到呢?不知道大家注意到这句代码没 [self.navigationController pushViewController:vc animated:YES]; 这里NavigationController的pushViewController方法可以获取到被push的view,那么我们何不重写pushViewController方法,让view被push之前能够做一些设置呢?照这个思路,我们势必是要重写下这个函数了,但问题来了,怎么重写它?很简单,我们自己创建一个类,然后继承于NavigationController后就可以重写这个函数,然后在项目中使用我们自己的NavigationController类就好。废话不多说,直接看代码。

//这个类是继承于UINavigationController的
#import "JHNavigationController.h"

@interface JHNavigationController ()

@end

@implementation JHNavigationController

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

- (void)pushViewController:(UIViewController *)viewController animated:(BOOL)animated
{
    /**
     这里要特别注意,在系统为我们启动应用时,这个pushViewController会被调用,我们不希望程序一启动连最开始的ViewController也有backbutton,所以这个if很重要。
     为了自定义push过后的返回按钮,需要拦截pushViewController这个方法来设置。
     *  当系统第一次帮我们push的时候,4个view的childViewController.count为0,不会进到if中,所以不管是bottomBar还是leftBarButtonItem都是view自己的设置。如果push页面,此时view的childViewController.count大于0,那么就会进入if设置leftBarButtonItem和bottomBar了
     */
    if (self.childViewControllers.count > 0) {

        UIButton *backButton = [UIButton buttonWithType:UIButtonTypeCustom];

        //设置返回按钮的title,默认title颜色和点击后title的颜色
        [backButton setTitle:@"返回" forState:UIControlStateNormal];
        [backButton setTitleColor:[UIColor blackColor] forState:UIControlStateNormal];
        [backButton setTitleColor:[UIColor redColor] forState:UIControlStateHighlighted];

        //设置button的大小
        backButton.size = CGSizeMake(100, 40);

        //设置返回按钮上的 < 箭头
        [backButton setImage:[UIImage imageNamed:@"navigationButtonReturn"] forState:UIControlStateNormal];
        [backButton setImage:[UIImage imageNamed:@"navigationButtonReturnClick"] forState:UIControlStateHighlighted];

        //设置button响应函数
        [backButton addTarget:self action:@selector(back:) forControlEvents:UIControlEventTouchUpInside];

        //push完成后隐藏底部工具栏
        viewController.hidesBottomBarWhenPushed = YES;

        //用backButton来填充UIBarButtonItem
        viewController.navigationItem.leftBarButtonItem = [[UIBarButtonItem alloc] initWithCustomView:backButton];
    }

    //!!!!!千万不能忘记调用父类的pushViewController方法,否则就不能正常push了
    [super pushViewController:viewController animated:animated];
}

- (void)back:(UIButton *)btn
{
    [self popViewControllerAnimated:YES];
}


@end

上面的代码提到了内边距,这里解释了什么是内边距

这一步完成后,在我们之前讲到的JHRootTabBarController的setupChildViewControllers函数中,就可以用我们自己的NavigationController来替换UINavigationController了。来张图看看效果。

项目总结2 UITabBarController为根视图的基础界面细节处理-返回按钮等_第4张图片

  • 3 大家有没有觉得上面的图有点儿不对劲?是不是返回按钮太过于靠左了?
    为了解决这个问题,我们可以设置button的内容显示模式为靠左显示,但这还不够,我们还需要设置下button的内边距,让内容更靠左。我们需要在重写的pushViewController函数中加入下面的代码
//设置返回按钮中内容(button中默认存在的左边的image和右边的label)为居中显示,以调整返回按钮中内容距左边界的距离
        backButton.contentHorizontalAlignment = UIControlContentHorizontalAlignmentLeft;
        //只靠设置内容居中还不够,我们需要再往左靠,这个时候需要设置内边距
        [backButton setContentEdgeInsets:UIEdgeInsetsMake(0, -10, 0, 0)];

我们来看看最终效果!

项目总结2 UITabBarController为根视图的基础界面细节处理-返回按钮等_第5张图片

最后提一点,我们这里用到了PCH文件,这个文件是预编译头文件,是全局的,在这个文件里包含了我写的分类,这样所有应用到分类内容的地方都不需要再导入头文件。PCH文件创建好后需要设置路径。

项目总结2 UITabBarController为根视图的基础界面细节处理-返回按钮等_第6张图片

大功告成! 项目地址点击这里,如果觉得有帮助,希望给个星星

你可能感兴趣的:(iOS)