[Note] CYLTabBarController

作者: _lemon | 来源:发表于2016-01-03 21:20 被阅读7198次

    “如果一个button有一部分超出父控件的范围了,这部分无法响应点击,如果想让它响应点击应该怎么做?”

    “这是一道送分题啊同学们!!!” [\债见]


    原地址:https://github.com/ChenYilong/CYLTabBarController

    只笔记一下核心的类吧,demo部分不写了,因为实在是封装得特别特别特别特别干净。


    CYLTabBarControllerConfig

    提供一个CYLTabBarController属性,接口做成只读,内部实现改成readwrite。给它配置了两个数组,viewControllers和tabBarItemsAttributes属性。README里提到了,因为用的是原生的控件,所以可以直接用[UITabBar appearance]来设置样式,比如选中时的背景。背景是画上去的,第一个imageContext画颜色,第二个imageContext画圆角。
    然后AppDelegate里面完成配置很简单,README里也写了。有一个细节是,设置主窗口的时候调了一个[self customizeInterface],这个方法里只做了一件事,调了一下[self setUpNavigationBarAppearance]。可以想象我肯定会把导航栏的设置方法直接写到设置主窗口的位置_(:з」∠)_…按作者这样写结构就好很多,以后再想添加别的设置外观的方法也会很方便,不会让设置主窗口的地方变得臃肿。


    CYLTabBarController

    CYLTabBarController这个类直接继承于系统的UITabBarController,对外的接口就是两个需要设置的数组viewControllerstabBarItemsAttributes

    setViewControllers:
    addOneChildViewController:WithTitle:normalImageName:selectedImageName:
    这两个方法做的是根据viewControllers和tabBarItemsAttributes来添加和设置container里的控制器和tabBarItem。
    关于container里的控制器,从父视图移除的写法:

    [vc willMoveToParentViewController:nil];
    [vc.view removeFromSuperview];
    [vc removeFromParentViewController];
    // [vc didMoveToParentViewController:nil] called automatically
    

    添加到父视图的写法:

    [self addChildViewController:vc];
    // [vc willMoveToParentViewController:self] called automatically
    [self.view addSubview:vc.view]; // or something like this.
    [vc didMoveToParentViewController:self];
    

    这里的写法是有顺序的。第一个场景在setViewControllers:里见到了,不过在demo里一开始的这个if好像从来就没进去过…因为setViewControllers只调了一次吧,如果调第二次重新设置viewControllers,原有的被添加的控制器和视图就需要都被移除了。第二个场景的写法没有见到,因为这里只是设置一下view controller array的setter,添加到父视图我猜应该是在切换视图的时候调用,这里直接继承于UITabBarController,这个实现就不用自己写了。
    这里还写了两个分类,一个内部的分类UIViewController(CYLTabBarControllerItemInternal),一个对外的分类UIViewController(CYLTabBarController),提供了一个属性cyl_tabBarControleller,注释里写了这是返回的TabBarController里包含的最顶层的view controller。因为TabBarController是一个container,里面装的控制器可以有很复杂的结构,这里找的是最顶层的那个控制器,比如在这个demo里就是navigation controller。做法是通过associated object(第一次读到活的associated object,一颗赛艇!),就是在把view controller array里面的控制器添加到TabBarController的时候,直接把它们都关联上tabBarController,然后需要返回的时候,通过objc_getAssociatedObject和parentViewController一层层往上找,直到找到当初被关联的那个控制器。demo里好像并没有调这个方法,应该是便于以后某些场景用吧。


    CYLTabBar

    hitTest:withEvent:
    先看这个面试时遇到的方法好了。这里event发生在TabBar上,point是采取TabBar的坐标,点击plusButton凸出的部分,可以看到point的y是负值,也就是超出TabBar区域了,调用UIView *result = [super hitTest:point withEvent:event];得到result = nil。要使event能响应的话,就得使point的值落在响应范围内,就要把坐标换到plusButton的坐标系,然后再调用hitTest:withEvent:,返回的result就是plusButton了。这里采用reverseObjectEnumerator我猜是因为plusButton是最后一个subview,这样返回速度会快一点?但是点击别的TabBarItem好像还是要轮一遍…所以我也不是特别懂是不是真的是这样优化的原因...
    我想了一下如果像以下这样写会不会快一点呢我不是很确定...(嗯这个地方已经询问过作者,提了个pr然后merge啦(๑• . •๑) )

    - (UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event
    {
        if (!self.clipsToBounds && !self.hidden && self.alpha > 0) {
            UIView *result = [super hitTest:point withEvent:event];
            if (result) {
                return result;
            }
            else {
                for (UIView *subview in self.subviews.reverseObjectEnumerator) {
                    CGPoint subPoint = [subview convertPoint:point fromView:self];
                    result = [subview hitTest:subPoint withEvent:event];
                    if (result) {
                        return result;
                    }
                }
            }
        }
        return nil;
    }
    

    layoutSubviews
    这个方法比较长,不过不是很复杂,做的是调整plusButton和之后TabBarItem的位置。plusButton默认的是使底部贴在TabBar底部这样来计算位置(如果没有TabBar高就直接放中间)。只是修改后面TabBarButton位置的时候,x值和width值是分别做的修改,我改成一起修改好像没看出什么区别,不太懂这里为什么要写成分别修改呢....


    CYLPlusButton, CYLPlusButtonSubclass

    这两个类不太复杂,虽然我也是因为太弱了第一次见这种registerSubclass的用法…感觉CYLPlusButton存在的意义主要是为了设置了一个protocol以及提供了一个extern UIButton对象,嗯在之前的类里也多次用到了这个唯一的对象。然后CYLPlusButtonSubclass是继承于CYLPlusButton,通过实现协议方法还有一些其他方法,定制了一个plusButton,设置了它的行为。

    相关文章

      网友评论

      本文标题:[Note] CYLTabBarController

      本文链接:https://www.haomeiwen.com/subject/xkrohttx.html