1.通过ChildViewController实现view的切换
viewControlle中可以添加多个subView,在需要的时候显示出来;另一种方法是通过向parentViewController中可以添加多个childCiewController;来控制页面中的subView,降低代码耦合度;通过切换子视图控制器,可以显示不同的view;,替代之前的addSubView的管理。
本节通过类似百度新闻模块切换的界面来演示ChileViewController的应用:
文档结构:
代码演示:
001.
#
import
"MainViewController.h"
002.
#
import
"FirstViewController.h"
003.
#
import
"SecondViewController.h"
004.
#
import
"ThirdViewController.h"
005.
@interface
MainViewController ()
006.
@property
(nonatomic, strong) FirstViewController *firstVC;
007.
@property
(nonatomic, strong) SecondViewController *secondVC;
008.
@property
(nonatomic, strong) ThirdViewController *thirdVC;
009.
@property
(nonatomic, strong) UIViewController *currentVC;
010.
011.
@property
(nonatomic, strong) UIScrollView *headScrollView;
012.
@property
(nonatomic, strong) NSMutableArray *itemArray;
013.
@property
(nonatomic, strong) UIView *contentView;
014.
@end
015.
016.
@implementation
MainViewController
017.
- (
void
)loadView{
018.
[
super
loadView];
019.
[self initialization];
020.
}
021.
022.
- (
void
)viewDidLoad {
023.
[
super
viewDidLoad];
024.
[self loadBaseUI];
025.
}
026.
027.
- (
void
)initialization{
028.
_itemArray = [NSMutableArray arrayWithObjects:@
"头条"
,@
"今日"
,@
"焦点"
, nil];
029.
}
030.
031.
- (
void
)loadBaseUI{
032.
self.title = @
"首页"
;
033.
_headScrollView = [[UIScrollView alloc]initWithFrame:CGRectMake(
0
,
0
, [UIScreen mainScreen].bounds.size.width,
44
)];
034.
_headScrollView.backgroundColor = [UIColor colorWithWhite:
0.902
alpha:
1.000
];
035.
for
(
int
i =
0
; i<_itemArray.count; i++) {
036.
UIButton *itemButton = [[UIButton alloc]initWithFrame:CGRectMake(i*([UIScreen mainScreen].bounds.size.width/_itemArray.count),
0
, [UIScreen mainScreen].bounds.size.width/_itemArray.count,
44
)];
037.
itemButton.tag =
100
+i;
038.
itemButton.backgroundColor = [UIColor clearColor];
039.
NSDictionary *dic = @{NSForegroundColorAttributeName:[UIColor purpleColor],NSFontAttributeName:[UIFont systemFontOfSize:
14
.0f]};
040.
[itemButton setAttributedTitle:[[NSAttributedString alloc]initWithString:_itemArray[i] attributes:dic] forState:UIControlStateNormal];
041.
[itemButton addTarget:self action:
@selector
(buttonClick:) forControlEvents:UIControlEventTouchUpInside];
042.
[_headScrollView addSubview:itemButton];
043.
}
044.
[_headScrollView setContentSize:CGSizeMake([UIScreen mainScreen].bounds.size.width,
44
)];
045.
_headScrollView.showsHorizontalScrollIndicator = NO;
046.
_headScrollView.showsVerticalScrollIndicator = NO;
047.
[self.view addSubview:_headScrollView];
048.
049.
_contentView = [[UIView alloc]initWithFrame:CGRectMake(
0
,
44
, [UIScreen mainScreen].bounds.size.width, [UIScreen mainScreen].bounds.size.height -
44
-
64
)];
050.
_contentView.backgroundColor = [UIColor clearColor];
051.
[self.view addSubview:_contentView];
052.
053.
[self addSubControllers];
054.
}
055.
056.
#pragma mark - privatemethods
057.
- (
void
)addSubControllers{
058.
_firstVC = [[FirstViewController alloc]initWithNibName:@
"FirstViewController"
bundle:nil];
059.
[self addChildViewController:_firstVC];
060.
061.
_secondVC = [[SecondViewController alloc]initWithNibName:@
"SecondViewController"
bundle:nil];
062.
[self addChildViewController:_secondVC];
063.
064.
_thirdVC = [[ThirdViewController alloc]initWithNibName:@
"ThirdViewController"
bundle:nil];
065.
[self addChildViewController:_thirdVC];
066.
067.
//调整子视图控制器的Frame已适应容器View
068.
[self fitFrameForChildViewController:_firstVC];
069.
//设置默认显示在容器View的内容
070.
[self.contentView addSubview:_firstVC.view];
071.
072.
NSLog(@
"%@"
,NSStringFromCGRect(self.contentView.frame));
073.
NSLog(@
"%@"
,NSStringFromCGRect(_firstVC.view.frame));
074.
075.
_currentVC = _firstVC;
076.
}
077.
078.
- (
void
)buttonClick:(UIButton *)sender{
079.
if
((sender.tag ==
100
&& _currentVC == _firstVC) || (sender.tag ==
101
&& _currentVC == _secondVC) || (sender.tag ==
102
&& _currentVC == _thirdVC)) {
080.
return
;
081.
}
082.
switch
(sender.tag) {
083.
case
100
:{
084.
[self fitFrameForChildViewController:_firstVC];
085.
[self transitionFromOldViewController:_currentVC toNewViewController:_firstVC];
086.
}
087.
break
;
088.
case
101
:{
089.
[self fitFrameForChildViewController:_secondVC];
090.
[self transitionFromOldViewController:_currentVC toNewViewController:_secondVC];
091.
}
092.
break
;
093.
case
102
:{
094.
[self fitFrameForChildViewController:_thirdVC];
095.
[self transitionFromOldViewController:_currentVC toNewViewController:_thirdVC];
096.
}
097.
break
;
098.
}
099.
}
100.
101.
- (
void
)fitFrameForChildViewController:(UIViewController *)chileViewController{
102.
CGRect frame = self.contentView.frame;
103.
frame.origin.y =
0
;
104.
chileViewController.view.frame = frame;
105.
}
106.
107.
//转换子视图控制器
108.
- (
void
)transitionFromOldViewController:(UIViewController *)oldViewControllertoNewViewController:(UIViewController *)newViewController{
109.
[self transitionFromViewController:oldViewController toViewController:newViewController duration:
0.3
options:UIViewAnimationOptionTransitionCrossDissolve animations:nil completion:^(BOOL finished) {
110.
if
(finished) {
111.
[newViewController didMoveToParentViewController:self];
112.
_currentVC = newViewController;
113.
}
else
{
114.
_currentVC = oldViewController;
115.
}
116.
}];
117.
}
118.
119.
//移除所有子视图控制器
120.
- (
void
)removeAllChildViewControllers{
121.
for
(UIViewController *vc in self.childViewControllers) {
122.
[vc willMoveToParentViewController:nil];
123.
[vc removeFromParentViewController];
124.
}
125.
}
126.
127.
/**
128.
* 方法说明:
129.
* 1、addChildViewController:向父VC中添加子VC,添加之后自动调用willMoveToParentViewController:父VC
130.
* 2、removeFromParentViewController:将子VC从父VC中移除,移除之后自动调用
131.
didMoveToParentViewController:nil
132.
* 3、willMoveToParentViewController: 当向父VC添加子VC之后,该方法会自动调用。若要从父VC移除子VC,需要在移除之前调用该方法,传入参数nil。
133.
* 4、didMoveToParentViewController: 当向父VC添加子VC之后,该方法不会被自动调用,需要显示调用告诉编译器已经完成添加(事实上不调用该方法也不会有问题,不太明白); 从父VC移除子VC之后,该方法会自动调用,传入的参数为nil,所以不需要显示调用。
134.
*/
135.
136.
/**
137.
* 注意点:
138.
要想切换子视图控制器a/b,a/b必须均已添加到父视图控制器中,不然会报错
139.
*/
140.
@end
最终效果:(实现了3个视图之间的切换)
iOS开发 剖析网易新闻标签栏视图切换(addChildViewController属性介绍)
本来只是打算介绍一下addChildViewController这个方法的,正好今天朋友去换工作面试问到网易新闻标签栏效果的实现,就结合它,用个小Demo实例介绍一下:(具体解释都写在了Demo里面的注释)
//
// HMTMainViewController.m
// UIScrollView
//
// Created by HMT on 14-6-25.
// Copyright (c) 2014年 humingtao. All rights reserved.
//
#import "HMTMainViewController.h"
#import "HMTFirstViewController.h"
#import "HMTSecondViewController.h"
#import "HMTThirdViewController.h"
@interface HMTMainViewController () <UIScrollViewDelegate>
@property (nonatomic ,strong) HMTThirdViewController *thirdVC;
@property (nonatomic ,strong) HMTFirstViewController *firstVC;
@property (nonatomic ,strong) HMTSecondViewController *secondVC;
@property (nonatomic ,strong) UIViewController *currentVC;
@property (nonatomic ,strong) UIScrollView *headScrollView; // 顶部滚动视图
@property (nonatomic ,strong) NSArray *headArray;
@end
@implementation HMTMainViewController
- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil
{
self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
if (self) {
// Custom initialization
}
return self;
}
- (void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view.
self.navigationItem.title = @"网易新闻Demo";
self.headArray = @[@"头条",@"娱乐",@"体育",@"财经",@"科技",@"NBA",@"手机"];
/**
* automaticallyAdjustsScrollViewInsets 又被这个属性坑了
* 我"UI高级"里面一篇文章着重讲了它,大家可以去看看
*/
self.automaticallyAdjustsScrollViewInsets = NO;
self.headScrollView = [[UIScrollView alloc] initWithFrame:CGRectMake(0, 64, 320, 40)];
self.headScrollView.backgroundColor = [UIColor purpleColor];
self.headScrollView.contentSize = CGSizeMake(560, 0);
self.headScrollView.bounces = NO;
self.headScrollView.pagingEnabled = YES;
[self.view addSubview:self.headScrollView];
for (int i = 0; i < [self.headArray count]; i++) {
UIButton *button = [UIButton buttonWithType:UIButtonTypeSystem];
button.frame = CGRectMake(0 + i*80, 0, 80, 40);
[button setTitle:[self.headArray objectAtIndex:i] forState:UIControlStateNormal];
button.tag = i + 100;
[button addTarget:self action:@selector(didClickHeadButtonAction:) forControlEvents:UIControlEventTouchUpInside];
[self.headScrollView addSubview:button];
}
/*
苹果新的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:
*/
self.firstVC = [[HMTFirstViewController alloc] init];
[self.firstVC.view setFrame:CGRectMake(0, 104, 320, 464)];
[self addChildViewController:_firstVC];
self.secondVC = [[HMTSecondViewController alloc] init];
[self.secondVC.view setFrame:CGRectMake(0, 104, 320, 464)];
self.thirdVC = [[HMTThirdViewController alloc] init];
[self.thirdVC.view setFrame:CGRectMake(0, 104, 320, 464)];
// 默认,第一个视图(你会发现,全程就这一个用了addSubview)
[self.view addSubview:self.firstVC.view];
self.currentVC = self.firstVC;
}
- (void)didClickHeadButtonAction:(UIButton *)button
{
// 点击处于当前页面的按钮,直接跳出
if ((self.currentVC == self.firstVC && button.tag == 100)||(self.currentVC == self.secondVC && button.tag == 101.)) {
return;
}else{
// 展示2个,其余一样,自行补全噢
switch (button.tag) {
case 100:
[self replaceController:self.currentVC newController:self.firstVC];
break;
case 101:
[self replaceController:self.currentVC newController:self.secondVC];
break;
case 102:
//.......
break;
case 103:
//.......
break;
case 104:
//.......
break;
case 105:
//.......
break;
case 106:
//.......
break;
//.......
default:
break;
}
}
}
// 切换各个标签内容
- (void)replaceController:(UIViewController *)oldController newController:(UIViewController *)newController
{
/**
* 着重介绍一下它
* transitionFromViewController:toViewController:duration:options:animations:completion:
* fromViewController 当前显示在父视图控制器中的子视图控制器
* toViewController 将要显示的姿势图控制器
* duration 动画时间(这个属性,old friend 了 O(∩_∩)O)
* options 动画效果(渐变,从下往上等等,具体查看API)
* animations 转换过程中得动画
* completion 转换完成
*/
[self addChildViewController:newController];
[self transitionFromViewController:oldController toViewController:newController duration:2.0 options:UIViewAnimationOptionTransitionCrossDissolve animations:nil completion:^(BOOL finished) {
if (finished) {
[newController didMoveToParentViewController:self];
[oldController willMoveToParentViewController:nil];
[oldController removeFromParentViewController];
self.currentVC = newController;
}else{
self.currentVC = oldController;
}
}];
}