底部导航栏封装

时间:2022-09-23 21:55:02
1.将需要显示的视图封装到一个容器视图中,然后在容器视图中填充内容,传递事件。
2. 控制器负责得到数据,传递给视图让其显示
3. 数据被封装为数据模型类

底部导航栏封装我们先要明白的是 视图的层次逻辑关系还有思路。
1.底部导航栏是需要封装的,而且其中的视图需要能接收点击事件,来完成切换界面
2.当切换界面时,我们是否需要将视图的层次调整来达到导航栏一直在最上层的目的
3.多个界面的UI逻辑类似,内容不同,我们只需要给一个界面传递不同的内容,来实现界面切换,视图内容也变化?

首先滤清了这样的思路,也提出了这样的思路是否可以的疑问。下面就开始实现了。

1. 首先封装一个底部导航栏视图。  
**
 *   与系统导航栏导航实现原理类似
 
 */


#pragma mark - 初始化
+ (CustomTabbar *)tabbar {
    return [[[self class] alloc] init];
}

+ (CustomTabbar *)tabbarWithTabbarBlock:(myBlock)myBlock {
    CustomTabbar *tabbar = [CustomTabbar tabbar];
    tabbar.tabbarBlock = myBlock;
    return tabbar;
}

#pragma mark - 系统方法 用来设置frame
- (void)willMoveToSuperview:(UIView *)newSuperview {
    
    self.frame = CGRectMake(0, newSuperview.height-49, newSuperview.width, 49);
    self.backgroundColor = [UIColor lightGrayColor];
    
}

#pragma mark - 逻辑辅助功能
- (void)setBtnTitles:(NSArray *)btnTitles {
    
    _btnTitles = btnTitles;
    CGFloat btnW = self.width/btnTitles.count;
    NSArray *images = @[@"upomp_button_keyboard3",@"upomp_button_keyboard3_highlighted"];
    for (int i = 0; i < btnTitles.count; i++) {
        UIButton *btn = [UIButton buttonWithType:UIButtonTypeCustom];
        [self addSubview:btn];
        [self configButton:btn Image:images[0] selectedImage:images[1] title:btnTitles[i]];
        btn.frame = CGRectMake(i*btnW, 0, btnW, self.height);
        btn.tag = i;
        [btn addTarget:self action:@selector(btnClick:) forControlEvents:UIControlEventTouchUpInside];
    }
    [self btnClick:(UIButton *)[self.subviews objectAtIndex:0]];
}

- (void)configButton:(UIButton *)button
               Image:(NSString *)imageName
       selectedImage:(NSString *)selectedIamgeName
               title:(NSString *)title {
    [button setTitle:title forState:UIControlStateNormal];
    [button setBackgroundImage:[UIImage imageNamed:imageName] forState:UIControlStateNormal];
    [button setBackgroundImage:[UIImage imageNamed:selectedIamgeName] forState:UIControlStateSelected];
}



#pragma mark - 按钮响应事件
- (void)btnClick:(UIButton *)button {
    
    if (button.selected == YES) {
        return;
    }
    for (UIButton *button in self.subviews) {
        button.selected = NO;
    }
    button.selected = YES;
    self.tabbarBlock(self,button,button.tag);
    
}

1 我们将button封装到自定义容器视图上,并且将会通过block或者代理 将要完成的事情交给控制器来处理。 
2 在 视图被添加到父视图的时候,设置frame。这样我们的逻辑十分清晰。
3. 当视图接收到数据,我们将传过来的数据 来开始搭建UI,这就是所谓的逻辑辅助。一般在外部接口方法中实现,也就是setter方法。
容器视图的封装比较简单。
1. 将数据显示
2. 完成类的交互
  类的交互 可以用block或者代理
  1. block    <1. ① 在类内部声明一个block属性作为外部接口
② 在类的外部定义block代码块。即类的实例变量.block = .. 即让block属性找到block的地址
③ 在类内部可以随时调用,完成回调功能。
<2. ① 可以在方法中加入block参数
②   在类内部用block属性接收这个block参数
 或是直接调用block代码块
③   这个block参数如果被接收不被立即调用。可以选择在其他的时机调用,完成回调。

代理这里先不说了。





因为只有一个容器视图,我们需要点击底部导航栏,来完成切换界面,显示不同的数据和界面。
所以 容器视图如果被更新 即 界面切换,需要释放 然后重新加载。
- (void)viewDidLoad {
    
    [super viewDidLoad];
    
    CustomTabbar *tabbar = [CustomTabbar tabbarWithTabbarBlock:^(CustomTabbar *tabbar, UIButton *button, NSInteger index) {
        // 释放之前的对象
        [_contentView removeFromSuperview];
        YXContentView *contentView = [YXContentView contentView];
        _contentView = contentView;
        [self.view addSubview:_contentView];
        // 给予数据
        _contentView.dataArray = self.dataArray[index];
        // 调换位置,达到显示的效果
        [self.view bringSubviewToFront:_contentView];
        [self.view bringSubviewToFront:tabbar];
        
        [_contentView setMyBlock:^(YXContentView *contentView,UIButton *button,NSInteger index) {
            if (index >= 100) {
                index -= 100;
                NSLog(@"%@",[contentView.dataArray[index] valueForKey:@"price"]);
            } else
                NSLog(@"%@",[contentView.dataArray[index] valueForKey:@"icon"]);
        }];
    }];
   [self.view addSubview:tabbar];
    tabbar.btnTitles = @[@"OC",@"JAVA",@"C#"];
    
}