您的位置:首页 > 其它

自定义导航视图控制器切换

2016-01-02 21:06 459 查看
在iOS开发过程中,通常我们会使用UINavigationController,UITabbarController等苹果提供的视图控制器来切换我们的视图。在iOS5之前,如果要自定义容器视图控制器很麻烦,比如你要考虑到子视图的生命周期,当设备旋转时的情况等,好在iOS5中苹果提供了添加视图控制器(addChildViewController)等管理视图控制器的API,这样我们就能使用此API来自定义自己的视图控制器了,这篇文章只要介绍如何使用此API实现UITabbarController的基本功能。

开始

使用过UITabbarController的都知道,UITabbarController可以在多个UIViewController中切换,来显示多个界面,先来看一下层级关系:



TabbarController作为根视图,然后添加了一个ChildViewController,最后用户看到内容是ChildViewController的视图内容和底部的TabBar

首先我们新建一个新的工程,选择Single View Application,启用StoryBoard,将其默认的ViewController作为ContainerViewController,然后创建两个新的ViewController,分别作为两个childViewController,这样目录中就有这些文件:



我们先进入StoryBoard拖入两个UIButton,给两个button设置tag:



然后创建两个ViewController,这里我启用了xib,设置一下ViewController的背景色:



这里我一个设置了绿色,还有个设置了棕色,还分别在每个ViewController上添加了UILabel,用于区分

然后进入ContainerViewController.m,声明以下私有变量和方法:

view sourceprint?

1.
@interface
ContainerViewController () {

2.
FirstViewController *_firstViewController;

3.
SecondViewController *_secondViewController;

4.

5.
NSMutableArray *_viewControllers;

6.
}


- (IBAction)buttonTouched:(id)sender;

view sourceprint?

1.


FirstViewController和SecondViewController是两个ChildViewController,_viewControllers则是保存ChildViewController的数组,再去StoryBoard关联下点击事件



在viewDidLoad中初始化:

view sourceprint?

01.
- (
void
)viewDidLoad

02.
{

03.
[
super
viewDidLoad];

04.

05.
_viewControllers = [@[] mutableCopy];

06.
_firstViewController = [[FirstViewController alloc] initWithNibName:@
'FirstViewController'
bundle:nil];

07.
_secondViewController = [[SecondViewController alloc] initWithNibName:@
'SecondViewController'
bundle:nil];

08.

09.
[_viewControllers addObject:_firstViewController];

10.
[_viewControllers addObject:_secondViewController];

11.

12.
[self loadViewControllerAtIndex:
0
];

13.
}


实例化了两个ViewController,然后将两个ViewController添加至数组中

关键部分来了,loadViewControllerAtIndex用于切换视图控制器,以下是实现:

view sourceprint?

01.
- (
void
)loadViewControllerAtIndex:(NSInteger)index {

02.
NSInteger nextIndex =
0
;

03.
if
(index ==
0
) {

04.
nextIndex =
1
;

05.
}
else
if
(index ==
1
) {

06.
nextIndex =
0
;

07.
}

08.

09.
UIViewController *fromViewController = _viewControllers[nextIndex];
// 获取当前viewController

10.
UIViewController *toViewController = _viewControllers[index];
// 获取将要切换的viewController

11.

12.
  
//

13.
if
(self.childViewControllers.firstObject == toViewController) {

14.
return
;

15.
}

16.

17.
if
(self.childViewControllers.count >
0
) {

18.
self.view.userInteractionEnabled = NO;
// 切换过程中禁用操作,等切换动画结束后恢复

19.
[fromViewController willMoveToParentViewController:nil];
// fromViewController将要移除

20.
[self addChildViewController:toViewController];
// 将toViewController添加至ContainerViewController

21.

22.
    
// 设置view的frame

23.
if
(index ==
1
) {

24.
toViewController.view.frame = [self nextViewStartFrame];

25.
}
else
{

26.
toViewController.view.frame = [self preViewStartFrame];

27.
}

28.

29.
    
// 官方提供的切换动画API,在这里执行切换动画

30.
[self transitionFromViewController:fromViewController toViewController:toViewController duration:
0.25
options:UIViewAnimationOptionCurveEaseInOut animations:^{

31.
         
// 执行动画

32.
if
(index ==
1
) {

33.
fromViewController.view.frame = [self preViewStartFrame];

34.
toViewController.view.frame = [self newViewStartFrame];

35.
}
else
{

36.
fromViewController.view.frame = [self nextViewStartFrame];

37.
toViewController.view.frame = [self newViewStartFrame];

38.
}

39.
}completion:^(BOOL finished) {

40.
       
// 动画执行完毕,从父视图添加或移除层级关系

41.
if
(finished) {

42.
[toViewController didMoveToParentViewController:self];

43.
[fromViewController removeFromParentViewController];

44.
self.view.userInteractionEnabled = YES;

45.
}

46.
}];

47.
}
else
{

48.
[self addChildViewController:toViewController];

49.
[self.view addSubview:toViewController.view];

50.
[toViewController didMoveToParentViewController:self];

51.
}

52.
}


- (CGRect)newViewStartFrame {

returnCGRectMake(0.0, 0.0, 320.0, 500.0);

}

view sourceprint?

1.


- (CGRect)nextViewStartFrame {

returnCGRectMake(320.0, 0.0, 320.0, 500.0);

}

view sourceprint?

1.


- (CGRect)preViewStartFrame {

returnCGRectMake(-320.0, 0.0, 320.0, 500.0);

}

view sourceprint?

1.


这个函数用于切换视图,使用addChildViewController把要添加的ViewController添加至ContainerViewController,移除不需要显示的。添加一个ViewController有几个步骤:

1. [self addChildViewController:toViewController];  添加至当前viewController

2. [self.view addSubView:toViewController.view];   添加view至self.view中

3. [toViewController didMoveToParentViewController:self];  当添加完成后要调用此方法来告知已经移动到父视图控制器中

移除一个ViewController也有几个步骤:

1. [fromViewController willMoveToParentViewController:nil];  参数传入nil说明将要移除视图

2. [fromViewController.view removeFromSuperView];  从父视图中移除fromViewController.view

3. [fromViewController removeFromParentViewController];  将fromViewController从父视图层级中移除

想要添加和移除ViewController这几个步骤是必要的,但是这里由于使用了transitionFromViewController:toViewController:duration:options:animations:completion:这个方法,它会先将toViewController.view添加至superView,然后执行动画,所以省略了[self.view addSubView:toViewController.view]

这样切换函数就算完成了,然后我们实现按钮事件函数:

view sourceprint?

1.
- (IBAction)buttonTouched:(id)sender {

2.
if
(((UIButton *)sender).tag ==
1
) {

3.
[self loadViewControllerAtIndex:
0
];

4.
}
else
{

5.
[self loadViewControllerAtIndex:
1
];

6.
}

7.
}


点击不同的按钮切换不同的界面,最后运行效果如下:



这里只是大致实现了下切换效果,在iOS7中新增的UIViewControllerContextTransitioning和UIViewControllerAnimatedTransitioning增强了对自定义的切换,这篇文章做了详细说明http://objccn.io/issue-12-3/
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: