iOS开发-抽屉效果

抽屉效果以前比较多,现在看到的比较少,手Q和今日头条现在侧边滑动通过抽屉的方式实现,关于第三方的抽屉效果有很多,稍微对比了一下实用效果比较实用的有两个RESideMenu和MMDrawerController,网上也有人推荐PPRevealSideViewController单就星星的数量的数量而言和上面两个都不一个层级的,慎重选择。本文先来看一下两者的效果,然后介绍抽屉效果实现原理.

RESideMenu

RESlideMenu.gif

代码实现起来也很简单:

    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

MMControllers.gif

单从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可以在文中的底部的参考地址详细研究~

模拟实现

如果实际开发中无论是从时间还是从效果上看建议选择以上两者中的一种实现,以下只是作为抽屉效果的一点探索,与大家分享,只适用于学习:

抽屉模拟.gif

效果很简单,实现起来很简单,这里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)
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 201,784评论 5 474
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 84,745评论 2 378
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 148,702评论 0 335
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,229评论 1 272
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,245评论 5 363
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,376评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,798评论 3 393
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,471评论 0 256
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,655评论 1 295
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,485评论 2 318
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,535评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,235评论 3 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,793评论 3 304
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,863评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,096评论 1 258
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,654评论 2 348
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,233评论 2 341

推荐阅读更多精彩内容

  • 发现 关注 消息 iOS 第三方库、插件、知名博客总结 作者大灰狼的小绵羊哥哥关注 2017.06.26 09:4...
    肇东周阅读 11,991评论 4 60
  • 这是第二次感受写作收获,与第一次最大的不同是:开始喜欢接受生活中每天有写作的习惯了。 总结写作给自己生活带来的变化...
    唐薇阅读 261评论 2 2
  • bootstrap是最受欢迎的HTML、CSS、JS的框架,用于开发响应式布局,移动设备优先的项目是为所有开发者、...
    Man僵小鱼阅读 322评论 0 1