iOS-addChildViewController使用和选中下划线实现

一、为什么苹果在iOS5添加了addChildViewController?

苹果新的API增加了addChildViewController方法,并且希望我们在使用addSubview时,同时调用[self addChildViewController:child]方法将sub view对应的viewController也加到当前ViewController的管理中。
对于那些当前暂时不需要显示的subview,只通过addChildViewController把subViewController加进去;需要显示时再调用transitionFromViewController方法。将其添加进入底层的ViewController中。
这样做的好处:
1.无疑,对页面中的逻辑更加分明了。相应的View对应相应的ViewController。
2.当某个子View没有显示时,将不会被Load,减少了内存的使用。
3.当内存紧张时,没有Load的View将被首先释放,优化了程序的内存释放机制。
在iOS5中,ViewController中新添加了下面几个方法:
* addChildViewController:
* removeFromParentViewController
* transitionFromViewController:toViewController:duration:options:animations:completion:
* willMoveToParentViewController:
* didMoveToParentViewController:

能想到的其它的一些使用场景或者说是优势吧

  • 不以navVC管理的,transition需要动画的 (例如某些login模块相关有注册,忘记密码,修改密码等)
  • 容器vc
  • 左右联动,或上下联动
  • 条件显示,一个vc不是一直显示的view,且该view比较复杂,业务功能比较多

不管怎样,开发过程中还是看具体使用场景,addChildViewController本质优点还是清晰易管理,但是滥用的话也会造成vc耦合度太高的问题

二、该demo代码实现的功能

1.addChildViewController使用
2.选中下划线标识(两种实现方案)
3.切换标签下划线动画
4.头部标签headscrollview抽离封装
5.childViewController里子view布局时机注意事项

三、addChildViewController使用(代码有详细的注释和注意点)

主容器VC--MainViewController

//
//  MainViewController.m
//  测试addChildViewController
//  1、选中下划线标识(两种实现方案) 2、切换标签下划线动画 3、headscrollview抽离封装
//  Created by caohx on 2021/1/13.
//

#import "MainViewController.h"
#import "FirstViewController.h"
#import "SecondViewController.h"
#import "ThirdViewController.h"
#import "HeadTitlesScrollView.h"

static CGFloat headHeight = 40;

@interface MainViewController ()
@property (nonatomic, strong) HeadTitlesScrollView *headScrollView;
@property (nonatomic, strong) UIViewController *currentVC;
@property (nonatomic, strong) FirstViewController *firstVC;
@property (nonatomic, strong) SecondViewController *secondVC;
@property (nonatomic, strong) ThirdViewController *thirdVC;
@end

@implementation MainViewController

- (void)viewDidLoad {
    [super viewDidLoad];
    
    self.view.backgroundColor = [UIColor grayColor];
    self.automaticallyAdjustsScrollViewInsets = NO;
    
    [self setupSubViews];
    [self requestData];
}

/// 请求网络数据
- (void)requestData {
    //nothing
}

/// 初始化并布局子view
- (void)setupSubViews {
    NSArray *headTitles = @[@"第一个",@"第二个",@"第三个",@"第一个",@"第二个",@"第三个"];
    //初始换headTitleview
    self.headScrollView = [[HeadTitlesScrollView alloc] initWithFrame:CGRectMake(0, 0, ScreenW, 40) titles:headTitles];
    self.headScrollView.backgroundColor = [UIColor blueColor];
    [self.view addSubview:self.headScrollView];
    //点击头部标签回调事件
    __weak typeof(self) weakSelf = self;
    self.headScrollView.blockClickHeadTitle = ^(NSInteger btnTag) {
        [weakSelf clickHeadBtn:btnTag];
    };
    
    //初始化子vc
    CGFloat originY = headHeight;
    CGFloat childVCHeight = ScreenH - headHeight;
    self.firstVC = [FirstViewController new];
    self.firstVC.view.frame = CGRectMake(0, originY, ScreenW, childVCHeight);
    self.secondVC = [SecondViewController new];
    self.secondVC.view.frame = CGRectMake(0, originY, ScreenW-100, childVCHeight-100);
    self.thirdVC = [ThirdViewController new];
    self.thirdVC.view.frame = CGRectMake(0, originY, ScreenW, childVCHeight);
    
    //默认添加第一个子vc
    [self.view addSubview:self.firstVC.view]; //这个不能删除
    [self addChildViewController:self.firstVC];
    self.currentVC = self.firstVC;
}


/// 处理点击某个头部标签,展示对应的vc
/// @param btnTag 正在被点击按钮的tag
- (void)clickHeadBtn:(NSInteger)btnTag {
    //点击的是同一个则返回
    if (((self.currentVC == self.firstVC) && btnTag == 100) ||
        ((self.currentVC == self.secondVC) && btnTag == 101) ||
        ((self.currentVC == self.thirdVC) && btnTag == 102)) {
        return;
    }
    
    //改变子vc
    switch (btnTag) {
        case 100:
            //显示第一个vc
            [self replaceOldVC:self.currentVC toNewVC:self.firstVC];
            break;
        case 101:
            //显示第二个vc
            [self replaceOldVC:self.currentVC toNewVC:self.secondVC];
            break;
        case 102:
            //显示第三个vc
            [self replaceOldVC:self.currentVC toNewVC:self.thirdVC];
            break;
        default:
            break;
    }
}

- (void)replaceOldVC:(UIViewController*)oldVC toNewVC:(UIViewController*)newVC {
    [self addChildViewController:newVC];
    [self transitionFromViewController:self.currentVC toViewController:newVC duration:1 options:UIViewAnimationOptionTransitionCrossDissolve animations:nil completion:^(BOOL finished) {
        if (finished) {
            //下面两句删除不会影响
            [self.view addSubview:newVC.view];
            [newVC didMoveToParentViewController:self];
            //移除旧的的vc
            [oldVC willMoveToParentViewController:nil];
            [oldVC removeFromParentViewController];
            self.currentVC = newVC;
        }else {
            self.currentVC = oldVC;
        }
    }];
}

@end

抽离封装的HeadTitlesScrollView

#import "HeadTitlesScrollView.h"

//以下都可以暴露给外面,动态设置
static CGFloat headScrollViewHeight = 40;
static CGFloat headScrollViewBtnWidth = 100;
static CGFloat lineWidth = 50.f;
//按钮的样式:颜色,字体,背景色等
//底部线的样式:颜色,高度,宽度等

@interface HeadTitlesScrollView () 
@property (nonatomic, strong) UIScrollView *mainScrollView;
@property (nonatomic, strong) UILabel *bLine;
@property (nonatomic, strong) NSArray *arrTitles;
@property (nonatomic, strong) NSMutableArray *mutArrBtns;
@property (nonatomic, strong) NSMutableArray *mutArrBottomLines;
@end

@implementation HeadTitlesScrollView

#pragma mark- 初始化
- (instancetype)initWithFrame:(CGRect)frame titles:(NSArray*)titles {
    self = [super initWithFrame:frame];
    if (self) {
        self.backgroundColor = [UIColor whiteColor];
        self.arrTitles = titles.copy;
        self.mutArrBtns = [NSMutableArray array];
        self.mutArrBottomLines = [NSMutableArray array];
        headScrollViewHeight = self.frame.size.height;
        [self setupSubViews];
    }
    
    return self;
}

- (instancetype)initWithCoder:(NSCoder *)coder {
    NSAssert(NO, @"请使用initWithFrame:titles:初始化");
    return [self initWithFrame:CGRectZero titles:@[]];
}

- (instancetype)initWithFrame:(CGRect)frame {
    return [self initWithFrame:frame titles:@[]];
}

#pragma mark- 设置并布局子view
- (void)setupSubViews {
    //主scrollview
    self.mainScrollView = [[UIScrollView alloc] initWithFrame:CGRectMake(0, 0, ScreenW, headScrollViewHeight)];
    self.mainScrollView.backgroundColor = [UIColor blueColor];
    CGFloat contentSizeWidth = self.arrTitles.count*headScrollViewBtnWidth;
    self.mainScrollView.contentSize = CGSizeMake(contentSizeWidth, 0);
//    self.mainScrollView.pagingEnabled = YES;
    self.mainScrollView.scrollEnabled = YES;
    self.mainScrollView.bounces = NO;
    self.mainScrollView.showsHorizontalScrollIndicator = NO;
    [self addSubview:self.mainScrollView];
    
    //头部scrollview添加button 和 button初始化
    for (int i = 0; i

childViewController里子view布局时机注意

#import "SecondViewController.h"

@interface SecondViewController () 
@property (nonatomic, strong) UITableView *mainTb;
@end

@implementation SecondViewController

- (void)viewDidLoad {
    [super viewDidLoad];
    self.view.backgroundColor = [UIColor purpleColor];
    
//    //不能在这布局;该vc的view此时还没布局完成,取的会是主容器view的frame
//    [self.view addSubview:self.mainTb];
}

- (void)viewDidLayoutSubviews {
    [super viewDidLayoutSubviews];
    
    //子view正确布局时机
    [self.view addSubview:self.mainTb];
}

#pragma mark- UITableViewDatasource
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
    return 20;
}

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
    UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:@"cellid"];
    cell.textLabel.text = @"test";
    return cell;
}

#pragma mark- getter
- (UITableView *)mainTb {
    if (!_mainTb) {
        _mainTb = [[UITableView alloc] initWithFrame:CGRectMake(0, 0, self.view.frame.size.width, self.view.frame.size.height) style:UITableViewStylePlain];
        _mainTb.delegate = self;
        _mainTb.dataSource = self;
        _mainTb.rowHeight = 100;
        [_mainTb registerClass:[UITableViewCell class] forCellReuseIdentifier:@"cellid"];
    }
    return _mainTb;
}

- (void)dealloc
{
    NSLog(@"%s",__func__);
}

@end

效果图

iOS-addChildViewController使用和选中下划线实现_第1张图片
效果图,抱歉不会上传mp4视频

结束语

addChildViewController参考链接
本来想放demo地址的,但是觉得还是自己敲一遍比较好,主要代码都在上面,能力有限 有什么不对的地方,欢迎指正[Salute]

你可能感兴趣的:(iOS-addChildViewController使用和选中下划线实现)