简单抽屉效果的实现

就目前大部分App来说基本上都有关于抽屉效果的实现,比如QQ/微信等。所以,今天我们就来简单的实现一下。当然如果你想你的效果更好或者是封装成一个到哪里都能用的工具类,那就还需要下一些功夫了,我们这里知识简单的介绍怎么去实现,不过一般我们开发都是找别人做好的,也没必要烂肺时间,除非你真的是大牛或者闲的蛋疼。

其实关于抽屉效果就是界面有三个View,其实一个主View其他两个分别是左边和右边的View,我们分别为他们添加手势,实现左右滑动显示对应的View。

一:所以,首先我们需要在头文件中定义三个View的属性,来给外界调用,实现设置对应的属性和效果:

 @property (nonatomic, weak, readonly) UIView *mainV;

 @property (nonatomic, weak, readonly) UIView *leftV;

 @property (nonatomic, weak, readonly) UIView *rightV;

二:然后在实现文件中定义对应的宏,后面要用到:

 // @"frame"

 #define XMGkeyPath(objc, keyPath) @(((void)objc.keyPath, #keyPath))

 // 在宏里面如果在参数前添加了#,就会把参数变成C语言字符串

 // 获取屏幕的宽度
 #define screenW [UIScreen mainScreen].bounds.size.width

 // 获取屏幕的高度
 #define screenH [UIScreen mainScreen].bounds.size.height

相信这里有一个宏你们一定很陌生,由于本章主要介绍抽屉效果,宏不是本章的内容,如果你真的想了解或者不能看懂上面的含义清看大神王魏分享的:

宏定义的黑魔法 - 宏菜鸟起飞手册

三:在ViewDidLoad中调用下面这个方法实现三个View的创建:

 // 添加所有的子控件
 - (void)setUpAllChildView
 {
     // left
     UIView *leftV = [[UIView alloc] initWithFrame:self.view.bounds];
     leftV.backgroundColor = [UIColor greenColor];
     [self.view addSubview:leftV];
     _leftV = leftV;

     // right
     UIView *rightV = [[UIView alloc] initWithFrame:self.view.bounds];
     rightV.backgroundColor = [UIColor blueColor];
     [self.view addSubview:rightV];
     _rightV = rightV;

     // main
     UIView *mainV = [[UIView alloc] initWithFrame:self.view.bounds];
     mainV.backgroundColor = [UIColor redColor];
     [self.view addSubview:mainV];
     _mainV = mainV;
 }

四:在ViewDidLoad中为界面添加滑动手势:

     // 添加拖拽手势
     UIPanGestureRecognizer *pan = [[UIPanGestureRecognizer alloc] initWithTarget:self action:@selector(pan:)];

     [_mainV addGestureRecognizer:pan];
 

并且使用KVO监听frame的变化:

注意:这里是整篇文章中最重的地方,也是相对最难的地方,主要设置到的一些计算

     // KVO作用:时刻监听某个对象的某个属性的改变
     // _main frame属性的改变
     // Observer:观察者
     // KeyPath:监听的属性
     // NSKeyValueObservingOptionNew:表示监听新值的改变
     [_mainV addObserver:self forKeyPath:XMGkeyPath(_mainV, frame) options:NSKeyValueObservingOptionNew context:nil];
     

五:实现滑动手势的方法,和监听属性变化的方法:

 #define targetR 300

 #define targetL -200

 - (void)pan:(UIPanGestureRecognizer *)pan
 {
     // 获取手势的偏移量
     CGPoint transP = [pan translationInView:_mainV];
     // 获取x轴的偏移量,相对于上一次
     CGFloat offsetX = transP.x;
     // 修改最新的main.frame,
     _mainV.frame = [self frameWithOffsetX:offsetX];
     // 复位
     [pan setTranslation:CGPointZero inView:_mainV];
     // 判断下当前手指有没有抬起,表示手势结束
     if (pan.state == UIGestureRecognizerStateEnded) { // 手指抬起,定位
         // x>屏幕的一半,定位到右边某个位置
         CGFloat target = ;
         if (_mainV.frame.origin.x > screenW * 0.5) {
             target = targetR;
         }else if (CGRectGetMaxX(_mainV.frame) < screenW * 0.5){
             // 最大的x < 屏幕一半的时候,定义到左边某个位置
             target = targetL;
         }
         // 获取x轴的偏移量
         CGFloat offsetX = target - _mainV.frame.origin.x;
         [UIView animateWithDuration:0.25 animations:^{
             _mainV.frame = [self frameWithOffsetX:offsetX];
         }];
     }
 }

 #define XMGMaxY 100

 // 给定一个x轴的偏移量计算下最新main的frame
 - (CGRect)frameWithOffsetX:(CGFloat)offsetX
 {

     // 获取当前main的frame
     CGRect frame = _mainV.frame;

     // 计算当前的x,y,w,h
     // 获取最新的x
     CGFloat x = frame.origin.x + offsetX;

     // 获取最新的y
     CGFloat y = x / screenW * XMGMaxY;

     // 当用户往左边移动的时候,_main.x < 0,y需要增加,为正
     ) {
         y = -y;
     }
     // 获取最新的h
     CGFloat h = screenH -  * y;
     // 获取缩放比例
     CGFloat scale = h / screenH;
     // 获取最新的w
     CGFloat w = screenW * scale;
     return CGRectMake(x, y, w, h);
 }

属性监听方法:

 // 只要监听的属性一改变,就会调用
 - (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context
 {
     ) { // 往右滑动,显示左边控件,隐藏右边控件
         _rightV.hidden = YES;
     }){ // 往左滑动,显示右边控件
         _rightV.hidden = NO;
     }
 }

注意:还记得我们前面学通知的时候一般用完都会讲通知移除,这里的KVO也是同样,所以我就提前做了,方便后面忘了(实际开发中也是一样的)

 // 注意:当对象被销毁的时候,一定要注意移除观察者
 - (void)dealloc
 {
     // 移除观察者
     [_mainV removeObserver:self forKeyPath:XMGkeyPath(_mainV, frame)];
 }

六:为界面添加一个Tap手势,为了实现点一下屏幕还原

      // 给控制器的view添加一个点按

      UITapGestureRecognizer *tap = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(tap)];

      [self.view addGestureRecognizer:tap];

还原方法的实现:

 - (void)tap
 {
     ) {
         // 把_mainV还原最开始的位置

         [UIView animateWithDuration:0.25 animations:^{
             _mainV.frame = self.view.bounds;

         }];

     }
 }

下面就是最重的效果:

     

iOS开发——实用技术OC篇&简单抽屉效果的实现的更多相关文章

  1. iOS开发——实用技术OC篇&单例模式的实实现(ACR&MRC)

    单例模式的实实现(ACR&MRC) 在iOS开发中单例模式是一种非常常见的模式,虽然我们自己实现的比较少,但是,系统却提供了不少的到来模式给我们用,比如最常见的UIApplication,No ...

  2. iOS开发——实用技术OC篇&8行代码教你搞定导航控制器全屏滑动返回效果

    8行代码教你搞定导航控制器全屏滑动返回效果 前言 如果自定了导航控制器的自控制器的leftBarButtonItem,可能会引发边缘滑动pop效果的失灵,是由于 self.interactivePop ...

  3. ios开发——实用技术OC篇&地图与定位

    地图与定位 11.1 iOS定位服务 11.2 iOS地图 11.3 Web地图 1 iOS定位服务 iOS中有三个定位服务组件: Wifi定位,通过查询一个Wifi路由器的地理位置的信息.比较省电, ...

  4. iOS开发——实用技术OC篇&事件处理详解

    事件处理详解 一:事件处理 事件处理常见属性: 事件类型 @property(nonatomic,readonly) UIEventType     type; @property(nonatomic ...

  5. ios开发——实用技术OC篇》倒计时实现的两种方法

    倒计时实现的两种方法 timeFireMethod函数,timeFireMethod进行倒计时的一些操作,完成时把timer给invalidate掉就ok了,代码如下: secondsCountDow ...

  6. iOS开发——实战OC篇&环境搭建之Xib(玩转UINavigationController与UITabBarController)

    iOS开发——实战OC篇&环境搭建之Xib(玩转UINavigationController与UITabBarController)   前面我们介绍了StoryBoard这个新技术,和纯技术 ...

  7. iOS开发——实战OC篇&环境搭建之纯代码(玩转UINavigationController与UITabBarController)

    iOS开发——实战OC篇&环境搭建之纯代码(玩转UINavigationController与UITabBarController)   这里我们就直接上实例: 一:新建一个项目singleV ...

  8. ios开发——实用技术OC-Swift篇&触摸与手势识别

    iOS开发学习之触摸事件和手势识别   iOS的输入事件 触摸事件 手势识别 手机摇晃 一.iOS的输入事件   触摸事件(滑动.点击) 运动事件(摇一摇.手机倾斜.行走),不需要人为参与的 远程控制 ...

  9. iOS开发——实战OC篇&环境搭建之StoryBoard(玩转UINavigationController与UITabBarController)

      环境搭建之StoryBoard(玩转UINavigationController与UITabBarController)   研究了这么就IOS开发,都没有所处一个像样或者自己忙一点的项目.最近自 ...

随机推荐

  1. Window nginx+tomcat+https部署方案 支持ios9

    客户端和 Nginx 之间走的 HTTPS 通讯,而 Nginx 到 Tomcat 通过 proxy_pass 走的是普通 HTTP 连接. 下面是详细的配置(Nginx 端口 80/443,Tomc ...

  2. Iframe的应用以及父窗口和子窗口的相互访问

    点评:Iframe和FRAME的区别,方便大家以后在使用过程中根据实际需要取舍.- function getParentIFrameDocument(aID) { var rv = null; // ...

  3. NServiceBus-架构的原则

    自主性和松散耦合在设计时和运行时都是没有的事,任何技术都可以给你. 面向服务的架构(SOA)和事件驱动的体系结构提供了依据识别使用nservicebus. 战略领域驱动设计有助于弥合业务/IT鸿沟和驱 ...

  4. (phpmyadmin error)Login without a password is forbidden by configuration (see AllowNoPassword) in ubuntu

    1.Go to /etc/phpmyadmin/config.inc.php and open it your favorite editor. 2.Search for below line of ...

  5. CenotOS ip a

  6. LINQ标准查询操作符(三)——Aggregate、Average、Distinct、Except、Intersect、Union、Empty、DefaultIfEmpty、Range、Repeat

    七.聚合操作符 聚合函数将在序列上执行特定的计算,并返回单个值,如计算给定序列平均值.最大值等.共有7种LINQ聚合查询操作符:Aggregate.Average.Count.LongCount.Ma ...

  7. js闭包测试

    本文的诞生,源自近期打算做的一个关于javascript中的闭包的专题,由于需要解析闭包对垃圾回收的影响,特此针对不同的javascript引擎,做了相关的测试. 为了能从本文中得到需要的知识,看本文 ...

  8. Codeforces Round #367 (Div. 2) C. Hard problem(DP)

    Hard problem 题目链接: http://codeforces.com/contest/706/problem/C Description Vasiliy is fond of solvin ...

  9. Java对信号的处理

    本文主要包括Java如何处理信号,直接上代码. 1. 实现SignalHandler package com.chzhao.SignalTest; import sun.misc.*; @Suppre ...

  10. ESP8266调试问题

    1 串口连接电脑调试时,GPIO15必须接地,否则没响应 2发送退出透传指令“+++”时,必须取消勾选发送新行.发送别的指令时须勾选. 另外若所刷固件版本为[Vendor:www.ai-thinker ...