仿网易侧滑Demo-简单易懂好上手

 

                        仿网易侧滑Demo-简单易懂好上手

 

自我介绍下:大肠腰子汤(一个很骚气的id)。我的第一篇帖子。呵呵呵呵呵呵呵呵呵呵呵呵。

本人是个菜鸟,大家轻喷。否则等我厉害了。。。呵呵,别让我找到你的帖子。
此贴也就本菜鸟以一个菜鸟的思路,写出的一个菜鸟的解决方案,适合比我更菜的菜鸟,或者跟我一样的臭屌丝。

 

最近,大大们看到网易新闻,就心动了,也让我们做一个。。。。

做就做吧。。。希望做完了要给我涨工资。我好买皮肤。。。。

 

好了,闲话少说。抱着对知识的渴望,对党对人民的热爱,下面我们进入正题。

 

//割了大大的小小//

  1. shift + command + n,选择single View application,让我们一起嗨嗨皮皮的把新的项目创建起来!

  2. 啥都不用说,进去故事板,直接拽一个tabbarcontroller 进来

     


    就是这样,让我们做一个狂拽酷炫霸的码农。


  3. 下面说下解决思路。本屌丝以为,有两种解决方案:

      1,以tabbarcontroller作为rootviewcontroller,然后再tabbarvcontroller.view上加入侧滑手势。当往右滑动时,瞬间截图。然后加载menuView和该截图,覆盖掉原来

        的tabbarcontroller,随着手势移动,移动该截图,显示出menView。当选中menuView中的某个选项后,再通过类似的方法,运用截图,恢复。

      2,以tabbarcontroller作为rootviewcontroller,然后再tabbarvcontroller.view上加入手势,判断侧滑。当往右滑动时,就把tabbarcontroller.view往右移动,往左滑动则相反。

    经过深思熟虑,我选择了方案2。

    -----小明:"这是为什么呢??"

    -----大肠腰子汤:“因为你是沙比。”

    呵呵。言归正传,理由如下:

       1,想象,如果通过截图来操作,会非常麻烦。若你在滑动开始时,进行截图,则截图会消耗部分时间(据我估计大概有0.3s以上,我是iphone4做的 测试),如果用户滑动的快些,那这0.3s中并  不会出现滑动效果,并且在0.3s结束后,图片会突然跳到我手指滑动到的位置。试想下如果我在0.3s 内从坐标(0,0)滑动到(160,240),那会是多么差的用户体验。当然你可以说本屌丝  的手机烂,但你不能否认iphone4还是存在着很大一批 用户的。

      2,好吧,我们不在滑动的时候截图,而是预先截图,将图片保存起来。呵呵呵,我也天真的这么想。然后呢。。。然后我发现,我要不停的不停的截图。一旦界面发生变化,我就要截图。。。

      3,这是最牛x的理由。请我们打开网易新闻客户端,然后我们快速的从下往上滑动手指,让tableview绚丽地转起来。紧接着,我们滑动navgationbar,让menuView显示出来。然后你就看到 &*^的,tableview还在转,让我们一起为此而呵呵。

    好了,说了三条理由否认了解决方案1,那么我们开始实现解决方案2。如果亲,你有别的解决方案,请您本着对知识的渴望,对党对人民的热爱,大方地通知本屌丝以下。

     

  4. 思路出来了,下面就是码农的活了。

      首先我们定制tabbarcontroller:创建类SideMenuTabBarController ,继承:UITabBarController,实现UIGestureRecognizerDelegate协议。

    #import <UIKit/UIKit.h>
    
    @interface SideMenuTabBarController : UITabBarController <UIGestureRecognizerDelegate>
    
    @end


    千万不要忘了,进入storyboard,把tabbarcontroller的类改成咱们自定义的类。




    “是时候展现真正的技术了”。。。

    既然用了这么炸天的侧滑,我们当然不能把tabbar展示出来,不然还有什么意义。所以我们先隐藏tabbar:

    - (id) initWithCoder:(NSCoder *)aDecoder
    {
        self = [super initWithCoder:aDecoder];
        if(self)
        {
            self.tabBar.hidden = YES;
        }
        return self;
    }

     

    爽歪歪。command+run ,我看到了我雪白的模拟器。


  5. 下面在此进入sotryboard。还记得网易新闻能往左往右两侧滑动进入不同的menuView么。那我们也用两个view,同时创建leftviewcontroller和rightviewcontroller分别去管理他们。


    注意了,请分别给两个view设置storyboardID。这个的作用一会就能知道。

  6. 让我们在SideMenuTabBarController里面添加两个变量:
    @property (nonatomic, strong) LeftViewController *leftVC;
    @property (nonatomic, strong) RightViewController *rightVC;
    这两个view其实就是侧滑后两侧的menuview。
    随后,在SideMenuTabBarController的viewDidLoad方法中,初始化这两个变量。
    - (void)viewDidLoad
    {
        [super viewDidLoad];
        //初始化两侧的view
        UIStoryboard *storyBoard=[UIStoryboard storyboardWithName:@"Main" bundle:nil];
        _leftVC = [storyBoard instantiateViewControllerWithIdentifier:@"LEFT_SIDE_VC"];
        _rightVC = [storyBoard instantiateViewControllerWithIdentifier:@"RIGHT_SIDE_VC"];
        _leftVC.view.tag = SIDE_VIEW_TAG;
        _rightVC.view.tag = SIDE_VIEW_TAG;
    
      //给tabbbarController添加手势
        UIPanGestureRecognizer *panGesture = [[UIPanGestureRecognizer alloc] init];
        [panGesture addTarget:self action:@selector(handleGesture:)];
        panGesture.delegate = self;
        [self.view addGestureRecognizer:panGesture];
        [self setSelectedIndex:0];
    }

    额,忘了说了,在这个方法里,我们同时把手势加上去吧。
    -------------细心的小明:“我看到了,handleGesture方法”。
    -------------大肠腰子汤:“戴比”。。。。。。。

  7. 由于该类要多次获取window对象,我毫不犹豫的写了个方法:
    //获取window对象
    - (UIWindow *) getWindow
    {
       return [[[UIApplication sharedApplication] delegate] window];
    }

    好了,铺垫的差不多了。下面来点干货了。


    //手势回掉方法
    - (void) handleGesture:(UIPanGestureRecognizer *)panGusture
    {
        UIWindow *window = [self getWindow];
        CGPoint translationInView = [panGusture translationInView:window];
    
        
        switch (panGusture.state) {
            case UIGestureRecognizerStateBegan://手势开始
                {
                    originalX = self.view.frame.origin.x;
                }
                break;
            
            case UIGestureRecognizerStateChanged://手势进行中
                {
                    /*
                     *由于手指的移动最多为320像素
                     *因此以320作为分母
                     *由于translationInView.x获得手势在x轴的位移量
                     *因此加上originalX 可获得此时手指相对window的x坐标
                     *因而分子为translationInView.x + originalX
                     *系数为320 - 50 (50为移动结束后 剩余显示的值)
                     */
    float percentage = (translationInView.x + originalX)/320; CGRect frame = self.view.frame; frame.origin.x = percentage * (320 - 50); if(frame.origin.x > 0) [self setSideViewController:Left]; else [self setSideViewController:Right]; [self.view setFrame:frame]; } break; case UIGestureRecognizerStateEnded://手势结束 { float xPosition = 0; float x = self.view.frame.origin.x; /* *0,< | -270/0 *0,> | 270/0 *<,> | 0/-270 *>,< | 0/270 */ if(originalX == 0)//初始阶段 { //SLIDE_DISTANCE作为分界线 if(x < originalX - SLIDE_DISTANCE) xPosition = - 270; else if (x > SLIDE_DISTANCE) xPosition = 270; else xPosition = 0; } else if(originalX < - 250) { if(x < originalX - SLIDE_DISTANCE) xPosition = originalX; else xPosition = 0; } else if (originalX > 250) { if(x < originalX - SLIDE_DISTANCE) xPosition = 0; else xPosition = originalX; } CGRect frame = self.view.frame; frame.origin.x = xPosition; //动画 [UIView animateWithDuration:0.15 animations:^{ [self.view setFrame:frame]; }]; } break; default: break; } }

    好长的一段代码!!!让我们以欣赏的角度,来分析下这段代码的逻辑。--(轻喷please)
    首先我们获取手势在window中的的坐标,保存在translationInView中。
    然后我们伴随siwtch语句,一步步的解析:
    1)UIGestureRecognizerStateBegan
    手势开始时,很简单
    我们把self.view.origin.x保存在一个类变量中:originalX。该变量在interface中声明,此处不再赘述。

    2)UIGestureRecognizerStateChanged
    手势移动时:注释是这样写的:
               /*
                     *由于手指的移动最多为320像素
                     *因此以320作为分母
                     *由于translationInView.x获得手势在x轴的位移量
                     *因此加上originalX 可获得此时手指相对window的x坐标
                     *因而分子为translationInView.x + originalX
                     *系数为320 - 50 (50为移动结束后 剩余显示的值)
                    
    */
    很简单。我最多允许view移动270个像素,保留50像素宽度在屏幕上。因此要把手指的移动位置和屏幕宽度相除得到一个比例,用该比例获得tabbarcontroller.view的移动位置。 比例的算法为:(translationInView.x + originalX)/ 320。对于originalX,只可能为三个值:0,270,-270。
    3)UIGestureRecognizerStateEnded
    手势结束时:
    先定义两个变量 x和xPosition。x描述此刻view相对于window的x坐标,xPosition用于记录view的目的x坐标。
    同样有一段注释:

                    /*
                     *0,< | -270/0
                     *0,> | 270/0
                     *<,> | 0/-270
                     *>,< | 0/270
                     */
    解释下该段注释:

    以第一行为例:

    (0,< | -270/0):如果手势开始时候,tabbarcontrolle.view的x轴坐标为0,并且手势的移动方向为左,
    那么xPosition的值只可能为-270或者0。当xposition=-270表示往左移动成功,显示出右侧的menuView,
    当xposition=0表示往左移动失败,恢复tabbarcontroller.view的x坐标。

    以第三行注释为例:

    (<,> | 0/-270):如果手势开始时候,tabbarcontrolle.view的x轴坐标为-270,即tabbarcontroller.view往左偏移,只显示右侧部分的内容,
    并且手势的移动方向为又,
    那么xPosition的值只可能为270或者0。当xposition=0表示往左移动成功,显示出右侧的menuView,
    当xposition=-270表示往左移动失败,恢复tabbarcontroller.view的x坐标。

    以此类推,能得出7种情况,就是switch语句的逻辑内容。

    而我判断每种情况下,手势是否有效的标志是:该手势位移量是否超过 SLIDE_DISTANCE 。
    例如:x < originalX - SLIDE_DISTANCE
    #define SLIDE_DISTANCE 100
     

     

  8. ------------------------小明:“[self setSideViewController:Left];这是个什么方法”
    ------------------------大肠腰子汤:“”

  9. 好,下面我们来说说这个方法:
    因为往左或者往右滑动的时候,显示出的menuview会不同,所以我根据滑动的方向,来设置menuview:
    typedef enum
    {
        Left,
        Right
    }Side_Direction;
    
    //设置侧面vc
    - (void) setSideViewController:(Side_Direction) direction{
        //删除原本存在的last_view
        UIWindow *window = [self getWindow];
        UIView *side_view = [window viewWithTag:SIDE_VIEW_TAG];
        if(side_view)
        {
            if(direction == Left && side_view == _leftVC.view)
                return;
            if(direction == Right && side_view == _rightVC.view)
                return;
            [side_view removeFromSuperview];
        }
        //添加新的view
        if(direction == Left)
            [window insertSubview:_leftVC.view atIndex:0];
        else
            [window insertSubview:_rightVC.view atIndex:0];
    }



  10. 最后,为了能让menuView通知tabbarcontroller,设置selectedIndex,我们给SideMenuTabBarController新增方法:
    //显示选中的view
    - (void) showControllerAtIndex:(int) index;
    //显示选中的view
    - (void) showControllerAtIndex:(int) index
    {
        if(index >= self.viewControllers.count)
            return;
        [UIView animateWithDuration:0.2 animations:^{
            //消失动画
            CGRect disappearFrame = self.view.frame;
            if(disappearFrame.origin.x < 0)
                disappearFrame.origin.x = - 350;
            else
                disappearFrame.origin.x = 350;
            self.view.frame = disappearFrame;
            
        } completion:^(BOOL finished) {
            //重新显示
            [UIView animateWithDuration:0.3 animations:^{
                self.selectedIndex = index;
                CGRect frame = self.view.frame;
                frame.origin.x = 0;
                self.view.frame = frame;
            }];
    
        }];
    }

    很简单的推出推进的动画。大功告成。



    终于搞定了。测试以下爽歪歪。

    ------------------小明:“是不是少了点什么?”。

  11. 的确少了很多。
    比如:我们的手势何时该开启,何时不该开?。
    -------------大肠腰子汤:“这个视情况而定。比如使用navigationcontroller的时候应该防止和ios7自带的侧滑手势冲突等”。
    又比如:网易新闻侧滑后的的view会缩小,这个怎么实现?--------------大肠腰子汤:“据我观测,此功能目前只在ios7上有效。有可能是用了autolayout后,直接按比例缩小abbacontroller.view的size来实现”。



    一句话总结:能力有限,暂时只能做成这样 && 轻喷 && 好人一生平安。
    最后附上demo:http://download.csdn.net/detail/justalloc/6441779

  

 

转载于:https://www.cnblogs.com/JustAlloc/p/3381963.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值