读源码之RESideMenu
RESideMenu是github上比较出名的一个开源库,主要是实现侧滑菜单,现在有三千多个star了。效果如下。
据说创意来源于dribbble的一个设计,还是比较好看的。感兴趣的可以去github上搜residemenu,地址就不贴了,选择这个开源库主要原因是带大家学习一下创建一个自定义的viewcontroller容器是怎样的步骤。
其实视图容器大家每天都在用,什么navigationcontroller,tabbarcontroller,pageviewcontroller,可能第三个大家比较少用,系统相册的点击浏览大图,然后左右滑动可以看下一个图的那个页面就是pageviewcontroller,比较像tableviewcontroller,也是数据驱动的。
为什么要用视图容器相信也不用我赘述了,好处多多,想象一下如果navigationcontroller里存入栈的不是viewcontroller而是一个个view,估计你的主view类代码要超过一万行了。
大家都知道,navigationcontroller里push和pop是这么回事。
虽然图片丑了点,但是大概意思相信大家清楚。但是大家有没有想过,你每次执行
[self.navigationController pushViewController:vc1 animated:YES];
这句话的时候,系统到底干了什么?其实系统是这么做的。
[self addChildViewController:vc1]; // 1
vc1.view.frame = [self frameForContentController]; // 2
[self.view addSubview:vc1.view];
[vc1 didMoveToParentViewController:self]; // 3
这里的self你们可以当成navigationcontroller。
第一步,navigationcontroller用addChildViewController这个函数把vc1这个controller添加作为自己的子视图控制器。
第二步,设置vc1这个视图控制器里根view的frame。
第三步,把vc1.view添加到navigationcontroller.view上。
第四步,用didMoveToParentViewController这个方法通知已经push完毕。
说完push了,那我们说说pop这个操作。这个操作其实是这么回事。假设你在之前已经alloc和init完毕了这个叫vc1的Viewcontroller。
[vc1 willMoveToParentViewController:nil]; // 1
[vc1.view removeFromSuperview]; // 2
[vc1 removeFromParentViewController];
第一步,用willMoveToParentViewController这个方法,并把参数设置为nil,通知vc1即将被移除父视图控制器。
第二步,把vc1.view移除出父视图控制器的view。
第三步,然后用removeFromParentViewcontroller这个方法把vc1彻底移除。
(这就是我反复强调的套路,套路的意思就是你只须知其然,不知其所以然就行了。因为人设计API的时候就是这么设计的。你不用问为什么这么设计。)
官方文档地址在这里。https://developer.apple.com/library/ios/featuredarticles/ViewControllerPGforiPhoneOS/CreatingCustomContainerViewControllers/CreatingCustomContainerViewControllers.html#//apple_ref/doc/uid/TP40007457-CH18-SW6
当时我看到这的时候我以为我懂了,其实我不懂。
有下面几个问题。
1.父容器是不是在添加子视图控制器的时候只能加一个,如果加第二个子视图控制器的时候是不是得先remove掉前一个。
答案:废话,当然不是只能加一个,你push->push->push的时候明明addchildviewcontroller了三回,然后你pop->pop->pop的时候才会执行removefromparentViewcontroller。也是执行了3回。
2.假如父视图容器添加了3个子视图容器,到底能同时显示几个子视图容器的view,是不是只能显示一个?
答案:当然不是,如果你愿意,你可以同时显示一百个。因为frame就是你自己设置的。你想设置多少设置多少。
OK,相信你如果你理解了上面两个问题,你应该理解所谓的父视图控制器到底是个怎么回事。
那我们看下RESideMenu的源码。
RESideMenu *sideMenuViewController = [[RESideMenu alloc] initWithContentViewController:navigationController
leftMenuViewController:leftMenuViewController
rightMenuViewController:rightMenuViewController];
这是REsideMenu的一个初始化方法,其实方法名字挺容易理解的,设置了一个内容viewcontroller,这个内容viewcontroller是个navigationcontroller,然后添加了一个左菜单viewcontroller,和一个右菜单viewcontroller。
大家猜到没有,这个函数到底执行了什么操作?
很简单,执行了三次这个东西呗。
[self addChildViewController:content]; // 1
content.view.frame = [self frameForContentController]; // 2
[self.view addSubview:self.currentClientView];
[content didMoveToParentViewController:self];
那个content分别是我们的左菜单视图,右菜单视图和内容视图。
不信我们来看下他的源码。
哎,我还不信邪了。继续往下看。看到viewDidLoad()这个方法。

我就晓得我的判断没有错,还是有这个方法吧。那就是说在REsideMenu加载到viewdidload的时候,判断left和right存不存在,如果不为nil就让residemenu把这两个controller外加content controller添加为childviewcontroller。
需要注意的是这列添加子视图控制器view的顺序,先加left的view,再加right的view,再加content的view。那么你脑海里应该有个图,是content的view在最上头,因为人们进入app之后肯定第一眼看到的是内容视图,我不能一进去就让用户看见菜单视图对吧,得让用户用手势拉开或者点一下左上角的button(一般是三条杠的那种button,俗称汉堡button)这时候才会显示菜单视图。(一般都是这样啊,不排除有些奇葩app一进去就给人看菜单。)
那么重头戏来了,到底是怎么把左边菜单呼叫出来的,然后内容视图没完全消失,而是只漏出一部分。如图
然后我们在源码里找到这么一段
其实也蛮好懂的,为了显示左边菜单视图,把视图的hidden设成no,右侧视图的hidden设成yes,估计是之前都设成yes了,这里让左侧视图显示出来。然后就是设置左侧菜单的内容什么的。
然后添加动画,给contentviewcontroller的view做了个scale,估计是把contentviewcontroller的view压缩了一下,然后压缩之后改变contentViewContainer的center,哎等一下,怎么有个contentviewContainer?
我又往前面看了一下,哦,原来residemenu有两个成员变量是uiview类型的,一个用来放菜单子视图的view,一个用来放内容视图的view。
然后我们来梳理下流程。
1.当用户点击汉堡按钮来显示左菜单的时候,先把左视图的hidden设成no。这样左视图显示。
2.为了有第一张图的效果,把内容视图的view 做个transform里的scale,XY压缩的小一点,然后改变内容视图的center,让他靠右。
然后就形成了这种效果。
那么显示右边菜单应该也是差不多的流程。
那么基础流程懂了,其实剩余的就是怎么美化这些过程。
给大家体格问题,一般侧滑菜单这种东西都是为了点击菜单切换内容视图的,那么切换内容视图的时候用了哪个方法呢?
最后,可能有人好奇RESidemenu怎么做到随着手指向右滑动,然后动画慢慢执行的过程的。
那么仔细看看
- (void)panGestureRecognized:(UIPanGestureRecognizer *)recognizer
读源码之RESideMenu的更多相关文章
- [一起读源码]走进C#并发队列ConcurrentQueue的内部世界
决定从这篇文章开始,开一个读源码系列,不限制平台语言或工具,任何自己感兴趣的都会写.前几天碰到一个小问题又读了一遍ConcurrentQueue的源码,那就拿C#中比较常用的并发队列Concurren ...
- Java读源码之ReentrantLock
前言 ReentrantLock 可重入锁,应该是除了 synchronized 关键字外用的最多的线程同步手段了,虽然JVM维护者疯狂优化 synchronized 使其已经拥有了很好的性能.但 R ...
- Java读源码之ReentrantLock(2)
前言 本文是 ReentrantLock 源码的第二篇,第一篇主要介绍了公平锁非公平锁正常的加锁解锁流程,虽然表达能力有限不知道有没有讲清楚,本着不太监的原则,本文填补下第一篇中挖的坑. Java读源 ...
- Java读源码之CountDownLatch
前言 相信大家都挺熟悉 CountDownLatch 的,顾名思义就是一个栅栏,其主要作用是多线程环境下,让多个线程在栅栏门口等待,所有线程到齐后,栅栏打开程序继续执行. 案例 用一个最简单的案例引出 ...
- 阅读源码很重要,以logback为例,分享一个小白都能学会的读源码方法
作为一个程序员,经常需要读一些开源项目的源码.同时呢,读源码对我们也有很多好处: 1.提升自己 阅读优秀的代码,第一可以提升我们自身的编码水平,第二可以开拓我们写代码的思路,第三还可能让我们拿到大厂 ...
- 读源码【读mybatis的源码的思路】
✿ 需要掌握的编译器知识 ★ 编译器为eclipse为例子 调试准备工作(步骤:Window -> Show View ->...): □ 打开调试断点Breakpoint: □ 打开变量 ...
- 跟大佬一起读源码:CurrentHashMap的扩容机制
并发编程——ConcurrentHashMap#transfer() 扩容逐行分析 前言 ConcurrentHashMap 是并发中的重中之重,也是最常用的数据结构,之前的文章中,我们介绍了 put ...
- 跟着大彬读源码 - Redis 1 - 启动服务,程序都干了什么?
一直很羡慕那些能读 Redis 源码的童鞋,也一直想自己解读一遍,但迫于 C 大魔王的压力,解读日期遥遥无期. 相信很多小伙伴应该也都对或曾对源码感兴趣,但一来觉得自己不会 C 语言,二来也不知从何入 ...
- 跟着大彬读源码 - Redis 3 - 服务器如何响应客户端请求?(下)
继续我们上一节的讨论.服务器启动了,客户端也发送命令了.接下来,就要到服务器"表演"的时刻了. 1 服务器处理 服务器读取到命令请求后,会进行一系列的处理. 1.1 读取命令请求 ...
随机推荐
- BZOJ1481 : Navigation Game
设$f[i][j][k]$表示从最后一行某个$H$走到$(i,j)$且在第$i$行只经过了$(i,j)$,途中经过了$k$次$F$的最小代价. $A[i][j][k]$表示从下一行$\leq i$的某 ...
- BZOJ4546(原) : 三元组
设$f(x)=\sum_{x|d}p(d)$. 则$ans=\sum_{i=1}^n\sum_{j=1}^n\sum_{k=1}^n\mu(i)\mu(j)\mu(k)f(lcm(i,j))f(lcm ...
- Java 读取配置文件 Properties
String filePath="src/cn/ac/iscas/pebble/ufe/conf/id.properties"; InputStream in = new Buff ...
- POJ3177 & 求边双联通分量
题意: 给一张无向图,求加多少边使原图任意两点边双联通. SOL: 一个不会写边双点双强联通的傻逼. 一个结论:把一棵树变成满足条件的图需要加的边使入度为1的点数+1除以2.------>就是树 ...
- android presentation
对于双屏异显(lcd 和 hdmi 的双屏异显),android框架已经支持,但是底层接口功能还是要自己去实现,且需要底层驱动支持. 使用presentation 去画第二个display就好了. M ...
- 51Nod 1046 A^B Mod C Label:快速幂
给出3个正整数A B C,求A^B Mod C. 例如,3 5 8,3^5 Mod 8 = 3. Input 3个正整数A B C,中间用空格分隔.(1 <= A,B,C <= 10^ ...
- 【POJ】3071 Football
http://poj.org/problem?id=3071 题意:2^n支队伍进行淘汰赛,每一轮都是第一个与第二个,第三个与第四个比赛,给出了这些人之间的胜率,赢了的进入下一轮,相对位置不变.一共n ...
- HDU 4753 Fishhead’s Little Game(DFS)
题目链接 很繁琐的爆搜,最多要加2^12条边,暴力就可以,回溯那部分一直没有回溯好,写了一晚上...代码非常,非常难看..对了,还不是普通的爆搜,双向搜索博弈,以前记得看过,这次好像第一次写.. #i ...
- LightOJ 1245 数学题,找规律
1.LightOJ 1245 Harmonic Number (II) 数学题 2.总结:看了题解,很严谨,但又确实恶心的题 题意:求n/1+n/2+....+n/n,n<=2^31. ...
- 基于FSIOT_A 实验平台SAM3S4B cortex-M3的温湿度采集
作者:卢老师,华清远见嵌入式学院讲师. DHT11数字温湿度传感器是一款含有已校准数字信号输出的温湿度复合传感器.它应用专用的数字模块采集技术和温湿度传感器技术,确保产品具有极高的可靠性与卓越的长期稳 ...