控制器切换(网易新闻效果)
有的时候设计开发的app用了UITabBarController控制器后,跳转到相应的导航栏控制器,而导航栏的控制器又有子控制,再子控制器中实现控制器的切换一般都不再采用UITabBarController实现,而是自己设计相应的控制器切换按钮实现,类似于网易新闻那样的效果.
最终实现的效果如下,点击按钮 切换 控制器:
具体实现原理:
在AppDelegate的函数中设置主窗口:
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{ //初始化窗口
self.window = [[UIWindow alloc] init];
self.window.frame = [UIScreen mainScreen].bounds;
//设置主控制器
XCMainController *mainVc = [[XCMainController alloc] init];
UINavigationController *nav = [[UINavigationController alloc] initWithRootViewController:mainVc];
self.window.rootViewController = nav;
//显示
[self.window makeKeyAndVisible];
return YES;
}
思想:创建一个主控制,然后用主控制来管理各个子控制,同时自定义一个导航按钮切换View,在其中添加各个按钮,并实现代理方法,当点击了按钮后,可以在主控制实现其代理方法,然后就可以完成相应的控制器切换.
初始化主控制器:
#import "XCNavBar.h"
- (void)viewDidLoad{
[super viewDidLoad];
//设置导航栏题目
self.navigationItem.title = @"主控制器";
//添加导航条
XCNavBar *navBar = [[XCNavBar alloc] init];
navBar.backgroundColor = [UIColor whiteColor];
navBar.delegate = self;
navBar.frame = CGRectMake(0, navigationH, viewW, navBarH);
[self.view addSubview:navBar];
}
自定义导航按钮:
.h文件
typedef enum{//按钮类型
XCNavBarButtonTypeOne = 0,
XCNavBarButtonTypeTwo,
XCNavBarButtonTypeThree,
XCNavBarButtonTypeFour
} XCNavBarButtonType;
//代理实现
@class XCNavBar;
@protocol XCNavBarDelegate <NSObject>
@optional//可选的
- (void)navBar:(XCNavBar *)navBar didSelectedButton:(XCNavBarButtonType)buttonType;
@end
//属性方法
@property (nonatomic, weak) id<XCNavBarDelegate> delegate;
.m文件
//属性
@property (nonatomic, strong) UIButton *selectedBtn;
//具体方法
- (instancetype)initWithFrame:(CGRect)frame{
self = [super initWithFrame:frame];
if (self) {
//添加按钮
[self addButtonWithTitle:@"one" buttonType:XCNavBarButtonTypeOne];
[self addButtonWithTitle:@"two" buttonType:XCNavBarButtonTypeTwo];
[self addButtonWithTitle:@"three" buttonType:XCNavBarButtonTypeThree];
[self addButtonWithTitle:@"four" buttonType:XCNavBarButtonTypeFour];
}
return self;
}
//添加一个按钮
- (void)addButtonWithTitle:(NSString *)title buttonType:(XCNavBarButtonType)type{
UIButton *btn = [UIButton buttonWithType:UIButtonTypeCustom];
[btn setTitle:title forState:UIControlStateNormal];
[btn setTitleColor:[UIColor orangeColor] forState:UIControlStateNormal];
[btn setTitleColor:[UIColor darkGrayColor] forState:UIControlStateDisabled];
btn.tag = type;
[self addSubview:btn];
[btn addTarget:self action:@selector(btnClick:) forControlEvents:UIControlEventTouchUpInside];
if (type == XCNavBarButtonTypeOne){
[self btnClick:btn];
}
}
//监听按钮点击
- (void)btnClick:(UIButton *)btn{
self.selectedBtn.enabled = YES;
btn.enabled = NO;
self.selectedBtn = btn;
//实现代理方法
if ([self.delegate respondsToSelector:@selector(navBar:didSelectedButton:)]) {
[self.delegate navBar:self didSelectedButton:btn.tag];
}
}
//计算子控件的位置
- (void)layoutSubviews{
[super layoutSubviews];
NSInteger count = self.subviews.count;
CGFloat btnW = self.bounds.size.width / count;
CGFloat btnH = self.bounds.size.height;
CGFloat btnX = 0;
CGFloat btnY = 0;
for (int i = 0; i < count; i++) {
UIButton *btn = self.subviews[i];
btnX = i * btnW;
btn.frame = CGRectMake(btnX, btnY, btnW, btnH);
}
}
主控制器中添加自控制器,并实现控制器的相应切换
/** 屏幕宽度 */
#define viewW self.view.frame.size.width
/** 屏幕高度 */
#define viewH self.view.frame.size.height
/** 子控制器高度 */
#define subViewH (viewH - navigationH - navBarH)
/** 导航条高度 */
#define navigationH 64
/** 导航按钮高度 */
#define navBarH 44
/** 子控制器Y值 */
#define subViewY (navigationH + navBarH)
//属性
//强引用,否则会被释放
@property (nonatomic, strong) XCOneController *oneVc;
@property (nonatomic, strong) XCTwoViewController *twoVc;
@property (nonatomic, strong) XCThreeController *threeVc;
@property (nonatomic, strong) XCFourController *fourVc;
/** 当前控制器 */
@property (nonatomic, strong) UIViewController *currentView;
//具体方法
- (void)viewDidLoad{
[super viewDidLoad];
//添加自控制器
self.oneVc = [[XCOneController alloc] init];
self.oneVc.view.frame = CGRectMake(0, subViewY, viewW, subViewH);
[self addChildViewController:self.oneVc];
self.twoVc = [[XCTwoViewController alloc] init];
self.twoVc.view.frame = CGRectMake(0, subViewY, viewW, subViewH);
[self addChildViewController:self.twoVc];
self.threeVc = [[XCThreeController alloc] init];
self.threeVc.view.frame = CGRectMake(0, subViewY, viewW, subViewH);
[self addChildViewController:self.threeVc];
self.fourVc = [[XCFourController alloc] init];
self.fourVc.view.frame = CGRectMake(0, subViewY, viewW, subViewH);
[self addChildViewController:self.fourVc];
//设置默认控制器
self.currentView = self.oneVc;
[self.view addSubview:self.oneVc.view];
}
/**
* 控制器切换方法实现
*/
- (void)replaceOldViewController:(UIViewController *)oldVc toNewViewController:(UIViewController *)newVc{
//要切换的控制器为当前控制器,则直接返回
if (self.currentView == newVc) return;
/**
* transitionFromViewController:toViewController:duration:options:animations:completion:
* fromViewController 当前显示在父视图控制器中的子视图控制器
* toViewController 将要显示的姿势图控制器
* duration 动画时间(这个属性,old friend 了 O(∩_∩)O)
* options 动画效果(渐变,从下往上等等,具体查看API)UIViewAnimationOptionTransitionCrossDissolve
* animations 转换过程中得动画
* completion 转换完成
*/
[self addChildViewController:newVc];
[self transitionFromViewController:oldVc toViewController:newVc duration:0.25 options:UIViewAnimationOptionTransitionCrossDissolve animations:nil completion:^(BOOL finished) {
if (finished) {
[newVc didMoveToParentViewController:self];
[oldVc willMoveToParentViewController:nil];
[oldVc removeFromParentViewController];
self.currentView = newVc;
}else{
self.currentView = oldVc;
}
}];
}
最后在主控制器中导航按钮的实现代理方法,完成控制器的切换
#pragma mark - XCNavBarDelegate代理方法
- (void)navBar:(XCNavBar *)navBar didSelectedButton:(XCNavBarButtonType)buttonType{
switch (buttonType) {
case XCNavBarButtonTypeOne:
[self replaceOldViewController:self.currentView toNewViewController:self.oneVc];
break;
case XCNavBarButtonTypeTwo:
[self replaceOldViewController:self.currentView toNewViewController:self.twoVc];
break;
case XCNavBarButtonTypeThree:
[self replaceOldViewController:self.currentView toNewViewController:self.threeVc];
break;
case XCNavBarButtonTypeFour:
[self replaceOldViewController:self.currentView toNewViewController:self.fourVc];
break;
default:
break;
}
}
最后:源代码地址
github源码地址
不积跬步,无以至千里;不积小流,无以成江海。