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


懶得翻譯了。。都是很簡單的單詞,大家理解的哈

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容