抽屉效果以前比较多,现在看到的比较少,手Q和今日头条现在侧边滑动通过抽屉的方式实现,关于第三方的抽屉效果有很多,稍微对比了一下实用效果比较实用的有两个RESideMenu和MMDrawerController,网上也有人推荐PPRevealSideViewController单就星星的数量的数量而言和上面两个都不一个层级的,慎重选择。本文先来看一下两者的效果,然后介绍抽屉效果实现原理.
RESideMenu
代码实现起来也很简单:
UINavigationController *navigationController = [[UINavigationController alloc] initWithRootViewController:[[DEMOFirstViewController alloc] init]];
DEMOLeftMenuViewController *leftMenuViewController = [[DEMOLeftMenuViewController alloc] init];
DEMORightMenuViewController *rightMenuViewController = [[DEMORightMenuViewController alloc] init];
RESideMenu *sideMenuViewController = [[RESideMenu alloc] initWithContentViewController:navigationController
leftMenuViewController:leftMenuViewController
rightMenuViewController:rightMenuViewController];
sideMenuViewController.backgroundImage = [UIImage imageNamed:@"Stars"];
sideMenuViewController.menuPreferredStatusBarStyle = 1; // UIStatusBarStyleLightContent
sideMenuViewController.delegate = self;
sideMenuViewController.contentViewShadowColor = [UIColor blackColor];
sideMenuViewController.contentViewShadowOffset = CGSizeMake(0, 0);
sideMenuViewController.contentViewShadowOpacity = 0.6;
sideMenuViewController.contentViewShadowRadius = 12;
sideMenuViewController.contentViewShadowEnabled = YES;
self.window.rootViewController = sideMenuViewController;
抽屉的动画效果,通过内容控制器和抽屉控制器,统一的由RESlideMenu进行管理,RESlideMenu同样是继承自UIViewController,支持iOS6.0及其以上手机版本.
MMDrawerController
单从Demo的效果看,作者还是挺用心的,很赞,基本上你需要的效果都能实现,用来做今日头条的抽屉效果毫无压力。主体实现代码:
UIViewController * leftSideDrawerViewController = [[MMExampleLeftSideDrawerViewController alloc] init];
UIViewController * centerViewController = [[MMExampleCenterTableViewController alloc] init];
UIViewController * rightSideDrawerViewController = [[MMExampleRightSideDrawerViewController alloc] init];
UINavigationController * navigationController = [[MMNavigationController alloc] initWithRootViewController:centerViewController];
[navigationController setRestorationIdentifier:@"MMExampleCenterNavigationControllerRestorationKey"];
UINavigationController * rightSideNavController = [[MMNavigationController alloc] initWithRootViewController:rightSideDrawerViewController];
[rightSideNavController setRestorationIdentifier:@"MMExampleRightNavigationControllerRestorationKey"];
UINavigationController * leftSideNavController = [[MMNavigationController alloc] initWithRootViewController:leftSideDrawerViewController];
[leftSideNavController setRestorationIdentifier:@"MMExampleLeftNavigationControllerRestorationKey"];
self.drawerController = [[MMDrawerController alloc]
initWithCenterViewController:navigationController
leftDrawerViewController:leftSideNavController
rightDrawerViewController:rightSideNavController];
[self.drawerController setShowsShadow:NO];
[self.drawerController setRestorationIdentifier:@"MMDrawer"];
[self.drawerController setMaximumRightDrawerWidth:200.0];
[self.drawerController setOpenDrawerGestureModeMask:MMOpenDrawerGestureModeAll];
[self.drawerController setCloseDrawerGestureModeMask:MMCloseDrawerGestureModeAll];
//http://www.jianshu.com/users/24da48b2ddb3/latest_articles
[self.drawerController
setDrawerVisualStateBlock:^(MMDrawerController *drawerController, MMDrawerSide drawerSide, CGFloat percentVisible) {
MMDrawerControllerDrawerVisualStateBlock block;
block = [[MMExampleDrawerVisualStateManager sharedManager]
drawerVisualStateBlockForDrawerSide:drawerSide];
if(block){
block(drawerController, drawerSide, percentVisible);
}
}];
self.window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
UIColor * tintColor = [UIColor colorWithRed:29.0/255.0
green:173.0/255.0
blue:234.0/255.0
alpha:1.0];
[self.window setTintColor:tintColor];
[self.window setRootViewController:self.drawerController];
return YES;
从最上面的三行代码我们可以看到抽屉效果实现的逻辑是内容和侧边栏的一个集中控制器,关于详细的API可以在文中的底部的参考地址详细研究~
模拟实现
如果实际开发中无论是从时间还是从效果上看建议选择以上两者中的一种实现,以下只是作为抽屉效果的一点探索,与大家分享,只适用于学习:
效果很简单,实现起来很简单,这里UITableView展示内容,背景视图当做左右抽屉,偷了懒,UITableView拖动通过
UIPanGestureRecognizer
实现的,有人是通过UIResponder
中的touchesMoved和touchesEnded实现计算偏移量的代码:
UITouch *touch = [touches anyObject];
CGPoint currentPoint = [touch locationInView:self.tableView];
CGPoint prePoint = [touch previousLocationInView:self.tableView];
对于UITableView是无效的,内容如果是单纯的UIView是可以通过以上代码实现抽屉效果的;
数据初始化代码:
for (NSInteger i=0;i<5; i++) {
[self.dataSource addObject:[NSString stringWithFormat:@"FlyElephant-%ld",i]];
}
[self.view addSubview:self.leftDrawer];
UIPanGestureRecognizer *panGesture=[[UIPanGestureRecognizer alloc]initWithTarget:self action:@selector(panGestureRecognizer:)];
[self.tableView addGestureRecognizer:panGesture];
[self.view addSubview:self.tableView];
宏定义:
#define SCREENWIDTH [[UIScreen mainScreen] bounds].size.width
#define SCREENHEIGHT [[UIScreen mainScreen] bounds].size.height
#define MAXYOFFSET 200
#define ENDRIGHTX 200
#define ENDLEFTX -200</code></pre>
手势控制`panGestureRecognizer:(UIPanGestureRecognizer *)panGesture`代码:
CGPoint transition = [panGesture translationInView:self.tableView];
self.tableView.frame=[self panGestureOffset:transition.x];
[panGesture setTranslation:CGPointZero inView:self.tableView];
//拖动手势结束
if (panGesture.state==UIGestureRecognizerStateEnded) {
CGFloat originX =self.tableView.frame.origin.x;
CGFloat offsetX=0;
//大于屏幕的一半进入新的位置
if (originX > SCREENWIDTH*0.5) {
offsetX=ENDRIGHTX-originX;
}else if(originX < SCREENWIDTH*0.5 && originX > -SCREENWIDTH*0.5){
//小于屏幕的一半,大于屏幕负一半的时候,则恢复到初始状态
offsetX=offsetX-originX;
}else if (originX<-SCREENWIDTH*0.5){
offsetX=ENDLEFTX-originX;
}
[UIView animateWithDuration:0.5 animations:^{
self.tableView.frame=[self panGestureOffset:offsetX];
}];
}
偏移量`panGestureOffset:(CGFloat)offsetX`控制:
offsetX=self.tableView.frame.origin.x+offsetX;
CGFloat offsetY = offsetX/SCREENWIDTH * MAXYOFFSET;
//如果需要设置右边的抽屉,参数为负数,需要取绝对值
CGFloat scale = (SCREENHEIGHT-fabs(2*offsetY))/SCREENHEIGHT;
CGFloat height = SCREENHEIGHT*scale;
CGFloat width = SCREENWIDTH;
CGFloat x = offsetX;
CGFloat y = (SCREENHEIGHT- height)* 0.5;
return CGRectMake(x, y, width, height);
### 参考链接
[RESideMenu](https://github.com/romaonthego/RESideMenu)
[MMDrawerController](https://github.com/mutualmobile/MMDrawerController)
[FEDrawerMenu](https://github.com/SmallElephant/FEDrawerMenu/tree/master)