简单抽屉效果的实现

就目前大部分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. 我的日常工具——gdb篇

    我的日常工具——gdb篇 03 Apr 2014 1.gdb的原理 熟悉linux的同学面试官会问你用过gdb么?那好用过,知道gdb是怎么工作的么?然后直接傻眼... gdb是怎么接管一个进程?并且 ...

  2. 数据结构(12) -- 图的邻接矩阵的DFS和BFS

    //////////////////////////////////////////////////////// //图的邻接矩阵的DFS和BFS ////////////////////////// ...

  3. Mysql的AB复制(主从复制)原理及实现

    Mysql复制(replication)是一个异步的复制,从一个Mysql 实例(Master)复制到另一个Mysql 实例(Slave).实现整个主从复制,需要由Master服务器上的IO进程,和S ...

  4. 使用MockMvc测试Spring mvc Controller

    概述   对模块进行集成测试时,希望能够通过输入URL对Controller进行测试,如果通过启动服务器,建立http client进行测试,这样会使得测试变得很麻烦,比如,启动速度慢,测试验证不方便 ...

  5. 记录一个 关于 python 普通方法,静态方法和类方法 的介绍。@classmethod @staticmethod

    上班时间 只贴看到最厉害的答案 回头总结 http://stackoverflow.com/questions/12179271/python-classmethod-and-staticmethod ...

  6. 60分钟内从零起步驾驭Hive实战学习笔记

    本博文的主要内容是: 1. Hive本质解析 2. Hive安装实战 3. 使用Hive操作搜索引擎数据实战 SparkSQL前身是Shark,Shark强烈依赖于Hive.Spark原来没有做SQL ...

  7. 【原】创建Hive表,分号分隔符“;”引起的异常

    [障碍再现] 在创建支持Map数据结构的Hive表时,抛出如下异常 hive> create table tab_map(name string,info map<string,strin ...

  8. linux which 查看可执行文件的位置

    我们经常在linux要查找某个文件,但不知道放在哪里了,可以使用下面的一些命令来搜索:        which  查看可执行文件的位置.       whereis 查看文件的位置.         ...

  9. OracleCommand.CommandText 无效

    OracleCommand insertADataCmd = conn.CreateCommand(); insertBDataCmd.CommandText = SQL OracleParamete ...

  10. HDU 3920Clear All of Them I(状压DP)

    HDU 3920   Clear All of Them I 题目是说有2n个敌人,现在可以发n枚炮弹,每枚炮弹可以(可以且仅可以)打两个敌人,每一枚炮弹的花费等于它所行进的距离,现在要消灭所有的敌人 ...