zoukankan      html  css  js  c++  java
  • (六十三)自定义TabBar和TabBarButtonItem

    自定义TabBar


    先自定义一个UITabBarController,为了方便跳转与设定属性,借助系统的TabBarController的功能,但是要移除内部的控件然后自己添加一个View和多个按钮。


    首先要移除已有的TabBarItem,通过判断是否是TabBarItem,但是TabBarItem是私有类,不让直接判断。

    因此通过判断父类类型来检查。


    要得到这些控件,需要在viewWillAppear方法中:

    - (void)viewWillAppear:(BOOL)animated{
        
        [super viewWillAppear:animated];
        NSLog(@"%d",self.tabBar.subviews.count);
        
        for (UIView *chind in self.tabBar.subviews) {
            
            NSLog(@"%@",chind.superclass);
            
        }
        
    }


    查看打印可以发现,TabBarButtonItem的父类是UIControl,而UITabBar的父类是UIView。

    2015-03-08 16:36:41.244 myWeibo[4832:140039] 5

    2015-03-08 16:36:41.245 myWeibo[4832:140039] UIView

    2015-03-08 16:36:41.245 myWeibo[4832:140039] UIControl

    2015-03-08 16:36:41.245 myWeibo[4832:140039] UIControl

    2015-03-08 16:36:41.245 myWeibo[4832:140039] UIControl


    2015-03-08 16:36:41.245 myWeibo[4832:140039] UIControl


    注意,通过isKindOfClass方法,可以判断多态性,例如TabBarButtonItem继承自UIControl,那么使用这个方法判断是否是UIControl,会返回真。

    - (void)viewWillAppear:(BOOL)animated{
        
        [super viewWillAppear:animated];
        
        for (UIView *chind in self.tabBar.subviews) {
            
            if ([chind isKindOfClass:[UIControl class]]) {
                [chind removeFromSuperview];
            }
            
        }
        
    }

    虽然是自定义TabBar,但是为了方便设置各个部分的属性,还是先设置tabBarItem的属性,然后把tabBarItem作为一个模型使用,传给自定义的TabBar来设置,不要忘了用上面的办法把系统自带的barButton给移除。


    要自定义TabBar,首先自定义UIView用于绘制:


    定义一个方法,传入tabBarItem,在tabBar上新建一个按钮,注意在这个方法中不能设置尺寸等属性。

    - (void)addTabBarButtonWithItem:(UITabBarItem *)item{
        
        UIButton *button = [[UIButton alloc] init];
        [self addSubview:button];
        
        [button setTitle:item.title forState:UIControlStateNormal];
        [button setImage:item.image forState:UIControlStateNormal];
        [button setImage:item.selectedImage forState:UIControlStateSelected];
        
    }

    通过layoutSubviews方法设定子控件尺寸

    - (void)layoutSubviews{
        
        [super layoutSubviews];
        
        CGFloat buttonW = self.frame.size.width / self.subviews.count;
        CGFloat buttonH = self.frame.size.height;
    
        
        for (int index = 0; index < self.subviews.count; index ++) {
            
            UIButton *btn = self.subviews[index];
            CGFloat buttonX = buttonW * index;
            CGFloat buttonY = 0;
            btn.frame = CGRectMake(buttonX, buttonY, buttonW, buttonH);
            
        }
        
    }


    在控制器中,新建一个上面的View的成员变量,注意View使用weak即可:

    @property (nonatomic, weak) myTabBar *customTabBar;

    注意首先创建自定义tabBar,然后再进行后续的设置:

    利用原来的TabBar尺寸可以快速设定自定义TabBar尺寸,注意使用bounds(以自己为参考,x=y=0).

    - (void)setupTabBar{
        myTabBar *customTabBar = [[myTabBar alloc] init];
        customTabBar.backgroundColor = [UIColor grayColor];
        customTabBar.frame = self.tabBar.bounds;
        [self.tabBar addSubview:customTabBar];
        self.customTabBar = customTabBar;
    }


    注意先用强指针创建再指过去,否则会被释放。


    然后定义一个方法用于将一个子控制器的根控制器设为TabBar控制器,然后设置barItem:

    注意最后调用自定义View的方法向自定义TabBar上添加控件。

    - (void)setupChindViewController:(UIViewController *)chindVc title:(NSString *)title imageName:(NSString *)imageName selectedImageName:(NSString *)selectedImageName{
        
        chindVc.title = title;
        chindVc.tabBarItem.image = [UIImage imageWithName:imageName];
        if (iOS7) {
            chindVc.tabBarItem.selectedImage = [[UIImage imageWithName:selectedImageName] imageWithRenderingMode:UIImageRenderingModeAlwaysOriginal];
        }else{
            chindVc.tabBarItem.selectedImage = [UIImage imageWithName:selectedImageName];
        }
    
        UINavigationController *nav = [[UINavigationController alloc] initWithRootViewController:chindVc];
        [self addChildViewController:nav];
        
        [self.customTabBar addTabBarButtonWithItem:chindVc.tabBarItem];
    
    }

    多次调用完成每个视图的添加:

    - (void)setupAllChindViewControllers{
        // 首页
        HomeViewController *home = [[HomeViewController alloc] init];
        [self setupChindViewController:home title:@"首页" imageName:@"tabbar_home" selectedImageName:@"tabbar_home_selected"];
        
        // 消息
        MessageViewController *message = [[MessageViewController alloc] init];
        [self setupChindViewController:message title:@"消息" imageName:@"tabbar_message_center" selectedImageName:@"tabbar_message_center_selected"];
        
        // 广场
        DiscoverViewController *ground = [[DiscoverViewController alloc] init];
        [self setupChindViewController:ground title:@"广场" imageName:@"tabbar_discover" selectedImageName:@"tabbar_discover_selected"];
        
        // 我
        MyViewController *me = [[MyViewController alloc] init];
        [self setupChindViewController:me title:@"我" imageName:@"tabbar_profile" selectedImageName:@"tabbar_profile_selected”];
    
    }

    因此只需要先调用方法初始化tabBar,再调用上面的方法即可创建完毕,不要忘记viewWillAppear方法中移除原来的按钮。

    - (void)viewDidLoad {
        
        [super viewDidLoad];
        [self setupTabBar];
        [self setupAllChindViewControllers];
        
    }


    注意,因为先添加的自定义View又添加的barItem,因此自定义View在底层,因此如果不移除系统自带的barItem,会盖在上面。


    注意这样做完以后,按钮是左右结构,不符合barItem的上下结构,因此要自定义按钮,重写返回rect的方法来设定图片和标题位置。

    为了让二者居中,让按钮的图片水平铺满、竖直占据60%,标题也水平铺满,竖直占据40%,接着让内容居中即可。

    #define myTabBarButtonImageRatio 0.6
    - (CGRect)imageRectForContentRect:(CGRect)contentRect{
        return CGRectMake(0, 0, contentRect.size.width, contentRect.size.height * myTabBarButtonImageRatio);
    }
    - (CGRect)titleRectForContentRect:(CGRect)contentRect{
        CGFloat titleY = contentRect.size.height * myTabBarButtonImageRatio;
        return CGRectMake(0, titleY, contentRect.size.width, contentRect.size.height - titleY);
    }
    

    因为是自定义的按钮,因此可以将按钮的状态设置封装在内部,可以借鉴前面,传入item模型即可,给按钮类增加item成员变量,重写set方法:

    - (void)setItem:(UITabBarItem *)item{
        [self setTitle:item.title forState:UIControlStateNormal];
        [self setImage:item.image forState:UIControlStateNormal];
        [self setImage:item.selectedImage forState:UIControlStateSelected];  
    }


    因为按钮只有选中和普通两种状态,因此取消高亮功能,重写高亮方法,什么也不做:

    - (void)setHighlighted:(BOOL)highlighted{};

    对于一次性设置的属性,例如按钮的颜色等,放入initWithFrame方法:设置颜色如果使用rgb不要忘了/255.0

    - (id)initWithFrame:(CGRect)frame{
        self = [super initWithFrame:frame];
        if (self) {
            self.imageView.contentMode = UIViewContentModeCenter;
            self.titleLabel.textAlignment = NSTextAlignmentCenter;
            self.titleLabel.font = [UIFont systemFontOfSize:12];
            [self setTitleColor:myTabBarButtonColor forState:UIControlStateNormal];
            [self setTitleColor:myTabBarButtonSelectedColor forState:UIControlStateSelected];
            if (!iOS7) {
                [self setBackgroundImage:[UIImage imageNamed:@"tabbar_slider"] forState:UIControlStateSelected];
            }
        }
        return self;
    }
    


    这样设置完了以后,就完成了和系统一样的TabBar的样式,并且具有极高的自由度。

    但是还不能切换控制器,可以在添加按钮时将index绑定到tag,通过代理传递给TabBar控制器。


    给每个按钮绑定点击方法,设定选中:

    注意提前给TabBar控制器一个selectedBtn属性,来保存之前选中的按钮。

    - (void)buttonClick:(myTabBarButton *)btn{
        
        if ([self.delegate respondsToSelector:@selector(tabBar:didSelectButtonFrom:to:)]) {
            [self.delegate tabBar:self didSelectButtonFrom:self.selectedBtn.tag to:btn.tag];
        }
        
        self.selectedBtn.selected = NO;
        btn.selected = YES;
        self.selectedBtn = btn;
    }


    TabBarController通过selectedIndex可以切换内部绑定的控制器。

    注意from to是从原来选中的哪个跳到现在选中的这个。

    - (void)tabBar:(myTabBar *)tabBar didSelectButtonFrom:(int)from to:(int)to{ 
        self.selectedIndex = to;
    }

  • 相关阅读:
    [设计模式]门面模式
    [设计模式]装饰者模式
    IE8半透明不显示出文字
    解决IE6,IE7不能隐藏绝对定位溢出的内容
    [设计模式]适配器模式
    linux学习网站
    PPP协议解析
    c语言面试题__指针篇
    单链表反转
    16道C语言面试题
  • 原文地址:https://www.cnblogs.com/aiwz/p/6154184.html
Copyright © 2011-2022 走看看