iOS-自定义tabBarViewController- 以及关于添加,移除子控制器方法

本文会建一个自定义的tabBarController

--------------------------------------------

在开始之前,我们先了解一下  Adding and Removing a Child  ViewController方法

先看一下SDK:

/*

These two methods are public for container subclasses to call when transitioning between child

controllers. If they are overridden, the overrides should ensure to call the super. The parent argument in

both of these methods is nil when a child is being removed from its parent; otherwise it is equal to the new

parent view controller.

addChildViewController: will call [child willMoveToParentViewController:self] before adding the

child. However, it will not call didMoveToParentViewController:. It is expected that a container view

controller subclass will make this call after a transition to the new child has completed or, in the

case of no transition, immediately after the call to addChildViewController:. Similarly

removeFromParentViewController: does not call [self willMoveToParentViewController:nil] before removing the

child. This is also the responsibilty of the container subclass. Container subclasses will typically define

a method that transitions to a new child by first calling addChildViewController:, then executing a

transition which will add the new child's view into the view hierarchy of its parent, and finally will call

didMoveToParentViewController:. Similarly, subclasses will typically define a method that removes a child in

the reverse manner by first calling [child willMoveToParentViewController:nil].

*/

- (void)willMoveToParentViewController:(UIViewController *)parent NS_AVAILABLE_IOS(5_0);

- (void)didMoveToParentViewController:(UIViewController *)parent NS_AVAILABLE_IOS(5_0);


苹果新的API增加了addChildViewController方法,并且希望我们在使用addSubview时,同时调用[self addChildViewController:child]方法将sub view对应的viewController也加到当前ViewController的管理中。对于那些当前暂时不需要显示的subview,只通过addChildViewController把subViewController加进去。需要显示时再调用transitionFromViewController:toViewController:duration:options:animations:completion方法。

另外,当收到系统的Memory Warning的时候,系统也会自动把当前没有显示的subview unload掉,以节省内存。


---------------------

然后下面是添加,移除,转换三个方法的实现


1.Adding another view controller’s view to the container’s view hierarchy

- (void) displayContentController: (UIViewController*) content;

{

[self addChildViewController:content];                // 1

content.view.frame = [self frameForContentController]; // 2

[self.view addSubview:self.currentClientView];

[content didMoveToParentViewController:self];          // 3

}

Here’s what the code does:

It calls the container’s addChildViewController: method to add the child. Calling the addChildViewController: method also calls the child’s willMoveToParentViewController: method automatically.

It accesses the child’s view property to retrieve the view and adds it to its own view hierarchy. The container sets the child’s size and position before adding the view; containers always choose where the child’s content appears. Although this example does this by explicitly setting the frame, you could also use layout constraints to determine the view’s position.

It explicitly calls the child’s didMoveToParentViewController: method to signal that the operation is complete.

Eventually, you want to be able to remove the child’s view from the view hierarchy. In this case, shown in Listing 14-2, you perform the steps in reverse.


----------

2.Removing another view controller’s view to the container’s view hierarchy

- (void) hideContentController: (UIViewController*) content

{

[content willMoveToParentViewController:nil];  // 1

[content.view removeFromSuperview];            // 2

[content removeFromParentViewController];      // 3

}

Here’s what this code does:

Calls the child’s willMoveToParentViewController: method with a parameter of nil to tell the child that it is being removed.

Cleans up the view hierarchy.

Calls the child’s removeFromParentViewController method to remove it from the container. Calling the removeFromParentViewController method automatically calls the child’s didMoveToParentViewController: method.

For a container with essentially static content, adding and removing view controllers is as simple as that. Whenever you want to add a new view, add the new view controller as a child first. After the view is removed, remove the child from the container. However, sometimes you want to animate a new child onto the screen while simultaneously removing another child. Listing 14-3 shows an example of how to do this.

----------

3.Transitioning between two view controllers

- (void) cycleFromViewController: (UIViewController*) oldC

toViewController: (UIViewController*) newC

{

[oldC willMoveToParentViewController:nil];                        // 1

[self addChildViewController:newC];

newC.view.frame = [self newViewStartFrame];                      // 2

CGRect endFrame = [self oldViewEndFrame];

[self transitionFromViewController: oldC toViewController: newC  // 3

duration: 0.25 options:0

animations:^{

newC.view.frame = oldC.view.frame;                      // 4

oldC.view.frame = endFrame;

}

completion:^(BOOL finished) {

[oldC removeFromParentViewController];                  // 5

[newC didMoveToParentViewController:self];

}];

}

Here’s what this code does:

Starts both view controller transitions.

Calculates two new frame positions used to perform the transition animation.

Calls the transitionFromViewController:toViewController:duration:options:animations:completion: method to perform the swap. This method automatically adds the new view, performs the animation, and then removes the old view.

The animation step to perform to get the views swapped.

When the transition completes, the view hierarchy is in its final state, so it finishes the operation by sending the final two notifications.

--------------------------------------------

要开始耍啦啦啦。。。


 在.h文件中,留下一些外部访问的属性和方法:

@property (nonatomic, copy, readonly) NSArray * viewControllers;

@property (nonatomic, copy, readonly) NSArray * barItemImages;

- (instancetype)initWithViewControllers:(NSArray *)viewControllers barItemImages:(NSArray *)barItemImages;

- (instancetype)initWithViewControllers:(NSArray *)viewControllers;


在.m文件中 首先会定义一些属性:

#import "DHTabViewController.h"


typedef NS_ENUM(NSUInteger, ViewTag) {

ButtonTag = 100

};

@interface DHTabViewController ()

@property (nonatomic, copy) NSArray * viewControllers;

@property (nonatomic, copy) NSArray * barItemImages;

@property (nonatomic, assign) NSUInteger selectedControllerIndex;

@property (nonatomic, strong) UIView * buttonContainerView;

@property (nonatomic, strong) UIView * childControllerContainerView;

- (void)initializeAppearance;

@end

--------------------------------------------

说明一下,我们应该遵循一定的代码规范(叫吗?我也不知道。。)

#init

#life circle

#system delegate

#custom delegate 

#private method

#getter setter

就是关于各种方法位置的顺序啦。。

--------------------------------------------

@implementation DHTabViewController

#pragma mark - initializer

- (instancetype)initWithViewControllers:(NSArray *)viewControllers

{

self = [self initWithViewControllers:viewControllers barItemImages:@[]];

return self;

}

- (instancetype)initWithViewControllers:(NSArray *)viewControllers barItemImages:(NSArray *)barItemImages

{

self = [super init];

if (self) {

self.selectedControllerIndex = 0;

self.viewControllers = viewControllers;

self.barItemImages = barItemImages;

}

return self;

}

- (instancetype)init

{

self = [self initWithViewControllers:@[]];

return self;

}


pragma mark - 生命周期

- (void)viewDidLoad {

[super viewDidLoad];

[self initializeAppearance];

}

#pragma mark - action/callback

- (void)action_onButton:(UIButton *)sender

{

NSUInteger index = sender.tag - ButtonTag;

if (index == self.selectedControllerIndex) {

return;

}

// 移除当前显示的controller

UIViewController * currentController = self.viewControllers[self.selectedControllerIndex];

[currentController.view removeFromSuperview];

[currentController removeFromParentViewController];

[currentController willMoveToParentViewController:nil];

// 加载选择的controller

UIViewController * selectedController = self.viewControllers[index];

[self addChildViewController:selectedController];

self.selectedControllerIndex = index;

}

#pragma mark - system protocol implentations

#pragma mark - custom protocol implentations

#pragma mark - private methods

- (void)initializeAppearance

{

if (self.viewControllers.count == 0) {

return;

}

[self.view addSubview:self.childControllerContainerView];

[self.view addSubview:self.buttonContainerView];

// 默认加载第一个controller的内容

UIViewController * firstViewController = self.viewControllers.firstObject;

[self addChildViewController:firstViewController];

// 初始化切换controller的按钮

CGFloat buttonWidth = CGRectGetWidth(self.view.bounds) / self.viewControllers.count;

[self.viewControllers enumerateObjectsUsingBlock:^(id obj, NSUInteger idx, BOOL *stop) {

UIButton * button = [UIButton buttonWithType:UIButtonTypeSystem];

[button setBackgroundColor:[UIColor yellowColor]];

[button addTarget:self action:@selector(action_onButton:) forControlEvents:UIControlEventTouchUpInside];

[button setFrame:CGRectMake(idx * buttonWidth, 0, buttonWidth, 40)];

if (self.barItemImages.count > 0) {

[button setImage:self.barItemImages[idx] forState:UIControlStateNormal];

} else {

[button setTitle:[NSString stringWithFormat:@"%ld",idx+1] forState:UIControlStateNormal];

}

button.tag = ButtonTag+idx;

[self.buttonContainerView addSubview:button];

}];

}

#pragma mark - override

- (void)addChildViewController:(UIViewController *)childController

{

[self.childControllerContainerView addSubview:childController.view];

childController.view.frame = CGRectOffset(self.view.frame, 0, 40);

[super addChildViewController:childController];

[childController didMoveToParentViewController:self];

}

#pragma mark - getter

- (UIView *)buttonContainerView

{

if (!_buttonContainerView) {

_buttonContainerView = ({

UIView * view = [[UIView alloc] initWithFrame:CGRectMake(0, 0, self.view.bounds.size.width, 40)];

[self childControllerContainerView];

view;

});

}

return _buttonContainerView;

}

- (UIView *)childControllerContainerView

{

if (!_childControllerContainerView) {

_childControllerContainerView = ({

UIView * view = [[UIView alloc] initWithFrame:self.view.bounds];

[self buttonContainerView];

view;

});

}

return _childControllerContainerView;

}

@end


懒得翻译了。。都是很简单的单词,大家理解的哈

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 196,099评论 5 462
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 82,473评论 2 373
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 143,229评论 0 325
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 52,570评论 1 267
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 61,427评论 5 358
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 46,335评论 1 273
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 36,737评论 3 386
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 35,392评论 0 254
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 39,693评论 1 294
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 34,730评论 2 312
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 36,512评论 1 326
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 32,349评论 3 314
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 37,750评论 3 299
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,017评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,290评论 1 251
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 41,706评论 2 342
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 40,904评论 2 335

推荐阅读更多精彩内容