最终效果图:Dock跟随HomeVC一起切换
要求:
当点击HomeVC里面的微博列表的某一行时候,
push到StatusDetail微博详情控制器,并且Dock也一起消失
当点击StatusDetail微博详情控制器上面的左边返回按钮,Dock也跟着HomeVC一起回来
HomeVC.m
// 点击列表中的一条微博,创建一个StatusDetailViewController,并为其成员status赋值(数据来源),并通过导航push入栈 - (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath { // 创建一个微博正文详情控制器, StatusDetailViewController *detailVC = [[StatusDetailViewController alloc] init]; // 为即将跳转的微博正文控制器,传递weibo数据(以供其显示用) StatusListCellFrame *statusListCellFrame = _statusCellFrames[indexPath.row]; detailVC.status = statusListCellFrame.status; // 通过导航控制器跳转过去 [self.navigationController pushViewController:detailVC animated:YES]; }
如上图所示,
主控制器(BeyondVC)的view包含两个部分:
1,上部的导航控制器 2,下面的Dock
上部的导航控制器的view又包括两个部分:
1,上部的导航条(push的时候,它始终不动)
2,下部的根控制器(HomeVC)(push的时候会动画切换)
为了让Dock和导航控制器的根控制(HomeVC)能一起滑过去,又能够一起滑回来,
必须让主控制器(BeyondVC)成为导航控制器的代理,
使之能够监听push动作之willShowViewController和didShowViewController方法
在下面的willShowViewController方法中,
先将Dock从主控制器(BeyondVC)上移除,然后添加到导航控制器的根控制(HomeVC)里面
导航控制器的代理方法 willShowViewController
#pragma mark - 导航控制器的代理方法 // 屏幕宽 320 #define kWinWidth self.view.bounds.width // 屏幕高 480 #define kWinHeight self.view.bounds.height // 顶部状态条 20 #define kStatusBarHeight 20 // 目的是,监听push动作,在新控制器将进入栈顶时,设置左边按钮为返回箭头,设置右边按钮为回到首页 - (void)navigationController:(UINavigationController *)navigationController willShowViewController:(UIViewController *)viewController animated:(BOOL)animated { //重要~~~~ // 先取得根控制器 UIViewController *rootVC = navigationController.viewControllers[0]; // 如果将要显示的控制器(将被push入栈的), 不是栈底控制器(根控制器),才需要设置左边为返回按钮,右边为首页按钮 if (viewController != rootVC) { // 左边的返回到上一个控制器 viewController.navigationItem.leftBarButtonItem = [UIBarButtonItem barButtonItemWithBgIcon:@"navigationbar_back.png" target:self action:@selector(popToPreviousVC)]; // 右边的回到首页按钮,即回到栈底控制器(即从详情页回到列表页) viewController.navigationItem.rightBarButtonItem = [UIBarButtonItem barButtonItemWithBgIcon:@"navigationbar_home.png" target:self action:@selector(backToRootVC)]; // 1,先拉长导航控制器的view的高度 为整个窗口的高度-20 (因为dock消失后,底部会多空出黑色的空间) navigationController.view.frame = CGRectMake(0, 20,320,480 - 20); // 2,先让Dock从主控制器(BeyondViewController)的view上移除 [_dock removeFromSuperview]; // 3,为了在Push下一个控制器,让dock和根控制器一起平移,所以,添加dock到导航控制器的根控制器的view上 ,并重新调整Dock在HomeVC的view中的Y值即可,注意导航不会移动,移的是导航的根控制器,而根控制器的原点(0 0)是 :20+导航栏高度44 // 如果根控制器是可以滚动的,则要注意y的原点是在tableView的顶部(当向下滚了一定的距离之后) if ([rootVC.view isKindOfClass:[UIScrollView class]]) { UIScrollView * scrollV = (UIScrollView *)rootVC.view; // dock的导航控制器的根控制器里面的y值 // 因为滚动之后,rootView的左上角到顶上很远的地方了 _dock.frame =CGRectMake(0, scrollV.contentOffset.y + 460 - kDockHeight, 320, kDockHeight ); } else { // dock的导航控制器的根控制器里面的y值 _dock.frame =CGRectMake(0, 480 - 20 - 2*kDockHeight, 320, kDockHeight ); } // 4,最后再添加dock到导航控制器的根控制器里面(rootVC界面上(即导航控制器的根控制器),目的是push新的VC的时候,让dock和导航控制器的根控制器一起平移到界面的左边去,当点击返回键的时候,dock又能和rootVC一起回来 [rootVC.view addSubview:_dock]; } }
在下面的didShowViewController方法中,
先将Dock从导航控制器的根控制(HomeVC)上移除,然后添加到主控制器(BeyondVC)里面
导航控制器的代理方法 didShowViewController
// 导航控制器的Y = 20,导航控制器的高度 = 总高度 - DOCK高度 - 20 #define kContentFrame CGRectMake(0, 20, self.view.frame.size.width, self.view.frame.size.height - kDockHeight - 20) // BeyondVC主控制器中,DOCK的Y = 总高度 - DOCK高度 #define KDockFrame CGRectMake(0, self.view.frame.size.height - kDockHeight, self.view.frame.size.width, kDockHeight) // 目的是,监听push动作,在新控制器已经显示的时候,将dock从导航控制器中移除,再又重新显示到主控制器 - (void)navigationController:(UINavigationController *)navigationController didShowViewController:(UIViewController *)viewController animated:(BOOL)animated { // 先取得导航 的栈底的根控制器 UIViewController *rootVC = navigationController.viewControllers[0]; // 如果要显示的控制器是根控制器,重新把Dock if (viewController == rootVC) { // 更改导航控制器view的frame // 导航控制器的Y = 20,导航控制器的高度 = 总高度 - DOCK高度 - 20 navigationController.view.frame = kContentFrame; // 将Dock先从栈底的根控制器rootVC上移除 [_dock removeFromSuperview]; // 再添加dock到BeyondViewController,DOCK的Y = 总高度 - DOCK高度 _dock.frame = KDockFrame; [self.view addSubview:_dock]; } }
这样就实现了,让主控制器里面的Dock跟随导航控制器的根控制器,一起消失,又一起回来~