实现一个简单的抽屉效果:

核心思想:KVO实现监听mainV的frame值的变化

核心代码:

  1. #import "ViewController.h"
  2.  
  3. // @"frame"
  4.  
  5. #define XMGkeyPath(objc, keyPath) @(((void)objc.keyPath, #keyPath))
  6.  
  7. // 在宏里面如果在参数前添加了#,就会把参数变成C语言字符串
  8.  
  9. // 获取屏幕的宽度
  10. #define screenW [UIScreen mainScreen].bounds.size.width
  11.  
  12. // 获取屏幕的高度
  13. #define screenH [UIScreen mainScreen].bounds.size.height
  14.  
  15. @interface ViewController ()
  16.  
  17. @end
  18.  
  19. @implementation ViewController
  20.  
  21. - (void)viewDidLoad {
  22. [super viewDidLoad];
  23.  
  24. // 添加所有的子控件
  25. [self setUpAllChildView];
  26.  
  27. // 添加拖拽手势
  28. UIPanGestureRecognizer *pan = [[UIPanGestureRecognizer alloc] initWithTarget:self action:@selector(pan:)];
  29.  
  30. [_mainV addGestureRecognizer:pan];
  31.  
  32. // KVO作用:时刻监听某个对象的某个属性的改变
  33. // _main frame属性的改变
  34. // Observer:观察者
  35. // KeyPath:监听的属性
  36. // NSKeyValueObservingOptionNew:表示监听新值的改变
  37. [_mainV addObserver:self forKeyPath:XMGkeyPath(_mainV, frame) options:NSKeyValueObservingOptionNew context:nil];
  38.  
  39. // 给控制器的view添加一个点按
  40.  
  41. UITapGestureRecognizer *tap = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(tap)];
  42.  
  43. [self.view addGestureRecognizer:tap];
  44.  
  45. }
  46.  
  47. - (void)tap
  48. {
  49. if (_mainV.frame.origin.x != 0) {
  50. // 把_mainV还原最开始的位置
  51.  
  52. [UIView animateWithDuration:0.25 animations:^{
  53. _mainV.frame = self.view.bounds;
  54.  
  55. }];
  56.  
  57. }
  58. }
  59.  
  60. // 只要监听的属性一改变,就会调用
  61. - (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context
  62. {
  63. if (_mainV.frame.origin.x > 0) { // 往右滑动,显示左边控件,隐藏右边控件
  64. _rightV.hidden = YES;
  65. }else if (_mainV.frame.origin.x < 0){ // 往左滑动,显示右边控件
  66. _rightV.hidden = NO;
  67. }
  68. }
  69.  
  70. // 注意:当对象被销毁的时候,一定要注意移除观察者
  71. - (void)dealloc
  72. {
  73. // 移除观察者
  74. [_mainV removeObserver:self forKeyPath:XMGkeyPath(_mainV, frame)];
  75. }
  76.  
  77. #define targetR 300
  78.  
  79. #define targetL -230
  80.  
  81. - (void)pan:(UIPanGestureRecognizer *)pan
  82. {
  83. // 获取手势的偏移量
  84. CGPoint transP = [pan translationInView:_mainV];
  85.  
  86. // 获取x轴的偏移量,相对于上一次
  87. CGFloat offsetX = transP.x;
  88.  
  89. // 修改最新的main.frame,
  90. _mainV.frame = [self frameWithOffsetX:offsetX];
  91.  
  92. // 复位
  93. [pan setTranslation:CGPointZero inView:_mainV];
  94.  
  95. // 判断下当前手指有没有抬起,表示手势结束
  96. if (pan.state == UIGestureRecognizerStateEnded) { // 手指抬起,定位
  97. // x>屏幕的一半,定位到右边某个位置
  98. CGFloat target = 0;
  99. if (_mainV.frame.origin.x > screenW * 0.5) {
  100. target = targetR;
  101. }else if (CGRectGetMaxX(_mainV.frame) < screenW * 0.5){
  102. // 最大的x < 屏幕一半的时候,定义到左边某个位置
  103. target = targetL;
  104. }
  105.  
  106. // 获取x轴的偏移量
  107. CGFloat offsetX = target - _mainV.frame.origin.x;
  108.  
  109. [UIView animateWithDuration:0.25 animations:^{
  110.  
  111. _mainV.frame = [self frameWithOffsetX:offsetX];
  112. }];
  113.  
  114. }
  115. }
  116.  
  117. #define XMGMaxY 100
  118.  
  119. // 给定一个x轴的偏移量计算下最新main的frame
  120. - (CGRect)frameWithOffsetX:(CGFloat)offsetX
  121. {
  122.  
  123. // 获取当前main的frame
  124. CGRect frame = _mainV.frame;
  125.  
  126. // 计算当前的x,y,w,h
  127. // 获取最新的x
  128. CGFloat x = frame.origin.x + offsetX;
  129.  
  130. // 获取最新的y
  131. CGFloat y = x / screenW * XMGMaxY;
  132.  
  133. // 当用户往左边移动的时候,_main.x < 0,y需要增加,为正
  134. if (frame.origin.x < 0) {
  135. y = -y;
  136. }
  137.  
  138. // 获取最新的h
  139. CGFloat h = screenH - 2 * y;
  140.  
  141. // 获取缩放比例
  142. CGFloat scale = h / screenH;
  143.  
  144. // 获取最新的w
  145. CGFloat w = screenW * scale;
  146.  
  147. return CGRectMake(x, y, w, h);
  148. }
  149.  
  150. // 添加所有的子控件
  151. - (void)setUpAllChildView
  152. {
  153. // left
  154. UIView *leftV = [[UIView alloc] initWithFrame:self.view.bounds];
  155. leftV.backgroundColor = [UIColor greenColor];
  156. [self.view addSubview:leftV];
  157. _leftV = leftV;
  158.  
  159. // right
  160. UIView *rightV = [[UIView alloc] initWithFrame:self.view.bounds];
  161. rightV.backgroundColor = [UIColor blueColor];
  162. [self.view addSubview:rightV];
  163. _rightV = rightV;
  164.  
  165. // main
  166. UIView *mainV = [[UIView alloc] initWithFrame:self.view.bounds];
  167. mainV.backgroundColor = [UIColor redColor];
  168. [self.view addSubview:mainV];
  169. _mainV = mainV;
  170. }
  171.  
  172. @end

用法:

继承ViewController

实现如下代码即可:

  1. #import "SlideViewController.h"
  2.  
  3. @interface SlideViewController ()
  4.  
  5. @end
  6.  
  7. @implementation SlideViewController
  8.  
  9. - (void)viewDidLoad{
  10. [super viewDidLoad];
  11. NSLog(@"%s",__func__);
  12.  
  13. // 创建一个tableView控制器
  14. UITableViewController *tableVc = [[UITableViewController alloc] init];
  15.  
  16. tableVc.view.frame = self.mainV.bounds;
  17.  
  18. [self.mainV addSubview:tableVc.view];
  19.  
  20. // 设计原理,如果A控制器的view成为b控制器view的子控件,那么这个A控制器必须成为B控制器的子控制器
  21. [self addChildViewController:tableVc];
  22.  
  23. UIViewController *VC = [[UIViewController alloc] init];
  24.  
  25. UIImageView *imagev = [[UIImageView alloc] initWithImage:[UIImage imageNamed:@"胸小别讲话"]];
  26.  
  27. // imagev.contentMode = UIViewContentModeScaleAspectFill;
  28.  
  29. imagev.frame = VC.view.frame;
  30.  
  31. [VC.view addSubview:imagev];
  32.  
  33. [self.rightV addSubview:VC.view];
  34.  
  35. [self addChildViewController:VC];
  36.  
  37. }
  38.  
  39. @end

github地址:https://github.com/chglog/drawer

iOS开发——高级篇——iOS抽屉效果实现原理的更多相关文章

  1. iOS开发——高级篇——iOS开发之网络安全密码学

    一.非对称加密 - RSA : + 公钥加密,私钥解密: + 私钥加密,公钥解密: + 只能通过因式分解来破解 二.对称加密 - DES - 3DES - AES (高级密码标准,美国国家安全局使用, ...

  2. iOS开发——高级篇——iOS 项目的目录结构

    最近闲来无事去面试一下iOS开发,让我感到吃惊的,面试官竟然问怎么分目录结构,还具体问每个子目录的文件名. 目录结构确实非常重要,面试官这么问,无疑是想窥探开发经验.清晰的目录结构,可让人一眼明白相应 ...

  3. iOS开发——高级篇——iOS涂鸦画板效果实现

    一个简单的绘图应用,模仿苹果自带软件备忘录里的涂鸦功能 核心代码 #import "DrawView.h" #import "DrawPath.h" @inte ...

  4. iOS开发——高级篇——iOS 强制退出程序APP代码

    1.先po代码 UIAlertView* alert = [[UIAlertView alloc] initWithTitle:self.exitapplication message:@" ...

  5. iOS开发——高级篇——iOS中如何选择delegate、通知、KVO(以及三者的区别)

      在开发IOS应用的时候,我们会经常遇到一个常见的问题:在不过分耦合的前提下,controllers[B]怎么进行通信.在IOS应用不断的出现三种模式来实现这种通信:1委托delegation2通知 ...

  6. iOS开发——高级篇——iOS中常见的设计模式(MVC/单例/委托/观察者)

    关于设计模式这个问题,在网上也找过一些资料,下面是我自己总结的,分享给大家 如果你刚接触设计模式,我们有好消息告诉你!首先,多亏了Cocoa的构建方式,你已经使用了许多的设计模式以及被鼓励的最佳实践. ...

  7. iOS开发——高级篇——iOS中为什么block用copy属性

    1. Block的声明和线程安全Block属性的声明,首先需要用copy修饰符,因为只有copy后的Block才会在堆中,栈中的Block的生命周期是和栈绑定的,可以参考之前的文章(iOS: 非ARC ...

  8. iOS开发——高级篇——iOS键盘的相关设置(UITextfield)

    一.键盘风格 UIKit框架支持8种风格键盘. typedef enum { UIKeyboardTypeDefault, // 默认键盘:支持所有字符 UIKeyboardTypeASCIICapa ...

  9. iOS开发——高级篇——iOS 中的 NSTimer

    以前的老代码在使用 NSTimer 时出现了内存泄露 NSTimer fire 我们先用 NSTimer 来做个简单的计时器,每隔5秒钟在控制台输出 Fire .比较想当然的做法是这样的: 1 2 3 ...

随机推荐

  1. running Fluent on Apocrita Cluster

    two files: code.sh, code.jou code.sh #!/bin/bash #$ -cwd #$ -j y #$ -m bea #$ -M k.ai@qmul.ac.uk #$ ...

  2. 【BZOJ 1076】[SCOI2008]奖励关(期望)

    Description 你正在玩你最喜欢的电子游戏,并且刚刚进入一个奖励关.在这个奖励关里,系统将依次随机抛出k次宝物, 每次你都可以选择吃或者不吃(必须在抛出下一个宝物之前做出选择,且现在决定不吃的 ...

  3. cf839c Journey

    大水题 #include <iostream> #include <cstdio> using namespace std; int n, du[100005], hea[10 ...

  4. ajax跨域访问总结

    1,jsonp的使用 就是script引用别的站点js,利用回调把内容传给这个js。 a需要引入b,在页面上引入b的js,里面有b的函数,在a中执行,就能拿到json了。 程序B中test.js的代码 ...

  5. JS获取所有LI中第三个<SPAN>

  6. Oracle中的特殊判式

    Oracle中的特殊判式 除了逻辑运算之外,Oracle提供了一些特殊判式.这些判式可以用来生成更加复杂和灵活的查询条件.本节将着重介绍以下几种判式. Between: 取值范围 In: 集合成员测试 ...

  7. apache kafka系列之server.properties配置文件参数说明

    每个kafka broker中配置文件server.properties默认必须配置的属性如下: broker.id=0num.network.threads=2num.io.threads=8soc ...

  8. 下载整个网页的方法,包括样式、图片、和js

    扒别人网站,不一定是要干邪恶的事(当然也有干的).有时候我们看到别人网站的功能很酷,想要自己试着实现一下.我们就需要扒一下这个页面,一方面可以线下修改学习,另一方面不会浪费时间在设计页面上,可以更关心 ...

  9. [NOIP1999] 提高组 洛谷P1016 旅行家的预算

    题目描述 一个旅行家想驾驶汽车以最少的费用从一个城市到另一个城市(假设出发时油箱是空的).给定两个城市之间的距离D1.汽车油箱的容量C(以升为单位).每升汽油能行驶的距离D2.出发点每升汽油价格P和沿 ...

  10. windows 配置 apache的多个站点

    windows 配置apache的多个站点 第一步打开apache的conf/extra/httpd-vhosts.conf,复制<VirtualHost></VirtualHost ...