简单抽屉效果的实现

就目前大部分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. 45个有新意的Photoshop教程和技巧

    图形制作者和网页设计师已经准备好迎接新的Adobe Photoshop 教程了.在大家喜欢背后有许多它的理由,诸如Adobe Photoshop很容易操作,学习起来十分简单,但最重要的一点是这款软件能 ...

  2. Flex之自定义事件

    1.通过dispatchEvent委托事件模式完成自定义事件: <?xml version="1.0" encoding="utf-8"?> < ...

  3. OC使用inline替代宏

    CG_INLINE voidGCDDelay(int64_t delayInSeconds,dispatch_block_t block){ dispatch_time_t popTime = dis ...

  4. tomcat 粗略笔记

    GlobalNamingResources 存在于server.xml中,定义全局公共数据源,如果host中有大量引用相同的数据源,那么可以都配在这里 <GlobalNamingResource ...

  5. KMP应用http://acm.hdu.edu.cn/showproblem.php?pid=2594

    riemann与marjorie拼接后riemannmarjorie前缀与后缀公共部分为 rie 长度为 3(即next[l] = next[14]的值,l为拼接后的长度)但:aaaa与aa拼接后aa ...

  6. Oracle Standby Database 实现方案

    Oracle Standby Database 实现方案  From: http://wanow.blog.hexun.com/4672755_d.html 字号:大 中 小 版本:V20060328 ...

  7. HDU 1561The more, The Better(树形DP)

    HDU 1561  The more, The Better 题目大意就不说了 直接DP[i][j]表示i为跟节点的子树上攻克j个城堡的所能获得的最多宝物的数量 DP[fa][j] = MAX{DP[ ...

  8. Domino 迁移到Exchange 服务器 之在Domino Server 创建用户!

    我们打开Lotus Admin,导航到注册,点击到需要设置的人,然后再选择验证者标识符选择相应的组织配置标识符:

  9. ASP.NET读取配置文件发送邮件

    之前写过一篇文章C#使用SMTP发送邮件 后来做了改进,改成读取独立的配置文件,本文只记录读取配置文件的部分,发送部分见上面的链接. 读取配置文件C#代码: using System; using S ...

  10. Gartner:Hype Cycle for Emerging Technologies-2013

      The “Hype Cycle for Emerging Technologies” report is the longest-running annual Hype Cycle, provid ...