iOS开发-抽屉效果

作者: FlyElephant | 来源:发表于2016-02-02 16:59 被阅读12072次

    抽屉效果以前比较多,现在看到的比较少,手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];
    

    宏定义:
    <pre><code>

    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
    MMDrawerController

    GitHub项目地址

    FEDrawerMenu

    相关文章

      网友评论

      本文标题:iOS开发-抽屉效果

      本文链接:https://www.haomeiwen.com/subject/tqyskttx.html