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

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

核心代码:

#import "ViewController.h"

// @"frame"

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

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

// 获取屏幕的宽度
#define screenW [UIScreen mainScreen].bounds.size.width // 获取屏幕的高度
#define screenH [UIScreen mainScreen].bounds.size.height @interface ViewController () @end @implementation ViewController - (void)viewDidLoad {
[super viewDidLoad]; // 添加所有的子控件
[self setUpAllChildView]; // 添加拖拽手势
UIPanGestureRecognizer *pan = [[UIPanGestureRecognizer alloc] initWithTarget:self action:@selector(pan:)]; [_mainV addGestureRecognizer:pan]; // KVO作用:时刻监听某个对象的某个属性的改变
// _main frame属性的改变
// Observer:观察者
// KeyPath:监听的属性
// NSKeyValueObservingOptionNew:表示监听新值的改变
[_mainV addObserver:self forKeyPath:XMGkeyPath(_mainV, frame) options:NSKeyValueObservingOptionNew context:nil]; // 给控制器的view添加一个点按 UITapGestureRecognizer *tap = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(tap)]; [self.view addGestureRecognizer:tap]; } - (void)tap
{
if (_mainV.frame.origin.x != 0) {
// 把_mainV还原最开始的位置 [UIView animateWithDuration:0.25 animations:^{
_mainV.frame = self.view.bounds; }]; }
} // 只要监听的属性一改变,就会调用
- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context
{
if (_mainV.frame.origin.x > 0) { // 往右滑动,显示左边控件,隐藏右边控件
_rightV.hidden = YES;
}else if (_mainV.frame.origin.x < 0){ // 往左滑动,显示右边控件
_rightV.hidden = NO;
}
} // 注意:当对象被销毁的时候,一定要注意移除观察者
- (void)dealloc
{
// 移除观察者
[_mainV removeObserver:self forKeyPath:XMGkeyPath(_mainV, frame)];
} #define targetR 300 #define targetL -230 - (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 = 0;
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需要增加,为正
if (frame.origin.x < 0) {
y = -y;
} // 获取最新的h
CGFloat h = screenH - 2 * y; // 获取缩放比例
CGFloat scale = h / screenH; // 获取最新的w
CGFloat w = screenW * scale; return CGRectMake(x, y, w, h);
} // 添加所有的子控件
- (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;
} @end

用法:

继承ViewController

实现如下代码即可:

#import "SlideViewController.h"

@interface SlideViewController ()

@end

@implementation SlideViewController

- (void)viewDidLoad{
[super viewDidLoad];
NSLog(@"%s",__func__); // 创建一个tableView控制器
UITableViewController *tableVc = [[UITableViewController alloc] init]; tableVc.view.frame = self.mainV.bounds; [self.mainV addSubview:tableVc.view]; // 设计原理,如果A控制器的view成为b控制器view的子控件,那么这个A控制器必须成为B控制器的子控制器
[self addChildViewController:tableVc]; UIViewController *VC = [[UIViewController alloc] init]; UIImageView *imagev = [[UIImageView alloc] initWithImage:[UIImage imageNamed:@"胸小别讲话"]]; // imagev.contentMode = UIViewContentModeScaleAspectFill; imagev.frame = VC.view.frame; [VC.view addSubview:imagev]; [self.rightV addSubview:VC.view]; [self addChildViewController:VC]; } @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. webservice学习第二天

    1 课程回顾 l 什么是webservice 远程调用技术:系统和系统之间的调用,获取远程系统里的业务数据 Webservice使用http传输SOAP协议的数据的一种远程调用技术 l Webserv ...

  2. Python+selenium(操作隐藏元素)

    测试过程中,偶尔会碰到一些页面的隐藏元素,如下,是小编举的一个简单的例子: test.html <html> <head></head> <body> ...

  3. python018 Python3 输入和输出

    Python3 输入和输出在前面几个章节中,我们其实已经接触了 Python 的输入输出的功能.本章节我们将具体介绍 Python 的输入输出. 输出格式美化Python两种输出值的方式: 表达式语句 ...

  4. Linux核心参数Shmmax,shmall,shmni

    Linux 下核心参数调整 kernel.shmmax shmmax是核心参数中最重要的参数之一,用于定义单个共享内存段的最大值,shmmax设置应足够大,能在一个共享内存段下容纳下整个的SGA,设置 ...

  5. BZOJ1583: [Usaco2009 Mar]Moon Mooing 哞哞叫

    给n<=4000000,c,a1,b1,c1,a2,b2,c2,以c为初始得到的数,每次可以把得到的某个数x进行操作f1(x)=a1*x/c1+b1,f2(x)=a2*x/c2+b2,求最后能得 ...

  6. 【转载】javascript中的函数对象

    原文地址:http://www.cnblogs.com/phpzxh/archive/2009/09/16/1568137.html[侵删] 在javascript中函数的申明方式有四种 下面代码中一 ...

  7. 解决ssh无操作自动断开[转载,已经验证]

    用SSH远程,如果几分钟没有任何操作,连接就会断开,必须重新登陆才行,非常麻烦,一般修改2个地方3项即可解决问题: 1.终端键入:echo $TMOUT       如果显示空白,表示没有设置,等于使 ...

  8. 50个必备的实用jQuery代码段(转载)

    本文会给你们展示50个jquery代码片段,这些代码能够给你的javascript项目提供帮助.其中的一些代码段是从jQuery1.4.2才开始支持的做法,另一些则是真正有用的函数或方法,他们能够帮助 ...

  9. python学习之-- 面向对象

    面向对象(简写:OOP) 面向对象编程定义:利用类和对象来创建各种模型,来实现对真实世界的描述. 优点:使程序更容易理解和维护以及扩展代码. 类定义:用来描述具有相同的属性和方法的对象的集合.(简单讲 ...

  10. P3366 最小生成树【模板】 洛谷

    https://www.luogu.org/problem/show?pid=3366 题目描述 如题,给出一个无向图,求出最小生成树,如果该图不连通,则输出orz 输入输出格式 输入格式: 第一行包 ...