本文會建一個自定義的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時,同時調(diào)用[self addChildViewController:child]方法將sub view對應(yīng)的viewController也加到當(dāng)前ViewController的管理中榔袋。對于那些當(dāng)前暫時不需要顯示的subview,只通過addChildViewController把subViewController加進(jìn)去铡俐。需要顯示時再調(diào)用transitionFromViewController:toViewController:duration:options:animations:completion方法凰兑。
另外,當(dāng)收到系統(tǒng)的Memory Warning的時候审丘,系統(tǒng)也會自動把當(dāng)前沒有顯示的subview unload掉吏够,以節(jié)省內(nèi)存。
---------------------
然后下面是添加,移除锅知,轉(zhuǎn)換三個方法的實(shí)現(xiàn)
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
--------------------------------------------
說明一下,我們應(yīng)該遵循一定的代碼規(guī)范(叫嗎昌妹?我也不知道捶枢。。)
#init
#life circle
#system delegate
#custom delegate?
#private method
#getter setter
就是關(guān)于各種方法位置的順序啦飞崖。烂叔。
--------------------------------------------
@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;
}
// 移除當(dāng)前顯示的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];
// 默認(rèn)加載第一個controller的內(nèi)容
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
懶得翻譯了。固歪。都是很簡單的單詞蒜鸡,大家理解的哈