mjrefresh源码分析
最近想自己写个下拉刷新的库,但是始终感觉无从下手,想想总是容易的。原理也很简单,真正要下手写的时候,呵呵。不得不说ios封装得很好,网上可以用的成熟的库也很多,也正是因为如此很多开发者也忽略了很多底层的东西,真正要去说清楚这些库的原理也说不清楚。以至于这两天说想自己写个下拉,蛋疼。。听很多从c++转到其他开发诸如c#或者ios或者java的朋友都说其实这些代码写起来都没有c++或者c写起来爽,不过开发的速度的确是c++没法比的。呵呵答。
今天研究了下mjrefresh,认真看了一下午,各处打断点,总算是清楚了它的流程。以下细细道来。
1、mjrefreshbaseview:
这个类是下拉视图的基类,包含三个对象,提示文字,下拉指示箭头和刷新旋转的视图。当正在拖拽时显示箭头,拖拽达到一定位置箭头转向,并且提示文字更改,松开后旋转动画开启,箭头图片隐藏。这个类的拓展类是mjrefreshfooterview和mjrefreshheaderview,分别表示scrollview的上拉刷新尾和下拉刷新头。
mjrefreshheaderview来说,mjfreshreshheaderview设置键值监听,监听拖拽过程中contentoffset这个值,通过判断不同拖拽状态下scrollview的值(代码中主要判断了contentoffset和scrollvieworiginalinset两个值)来判断拖拽的状态是正在拖拽,还是拖拽即将完成或者拖拽结束的,并且设置这个时候的状态state(mjrefreshbaseview成员变量,纪录此时uiscrollview拖拽状态)。看代码:
- (void)adjustStateWithContentOffset
{
// 当前的contentOffset
CGFloat currentOffsetY = self.scrollView.contentOffsetY;
// 头部控件刚好出现的offsetY
CGFloat happenOffsetY = - self.scrollViewOriginalInset.top; // 如果是向上滚动到看不见头部控件,直接返回
if (currentOffsetY >= happenOffsetY) return; if (self.scrollView.isDragging) {
// 普通 和 即将刷新 的临界点
CGFloat normal2pullingOffsetY = happenOffsetY - self.height; if (self.state == MJRefreshStateNormal && currentOffsetY < normal2pullingOffsetY) {
// 转为即将刷新状态
self.state = MJRefreshStatePulling;
} else if (self.state == MJRefreshStatePulling && currentOffsetY >= normal2pullingOffsetY) {
// 转为普通状态
self.state = MJRefreshStateNormal;
}
} else if (self.state == MJRefreshStatePulling) {// 即将刷新 && 手松开
// 开始刷新
self.state = MJRefreshStateRefreshing;
}
}
self.state代表这个contentoffset上一个值的uiscorllview状态,根据uiscrollview的值判断状态后并设置self.state,并修改刷新视图的提示文字,并修改箭头的指向。
- (void)setState:(MJRefreshState)state
{
// 1.一样的就直接返回
if (self.state == state) return; // 2.保存旧状态
MJRefreshState oldState = self.state; // 3.调用父类方法
[super setState:state]; // 4.根据状态执行不同的操作
switch (state) {
case MJRefreshStateNormal: // 下拉可以刷新
{
// 设置文字
self.statusLabel.text = MJRefreshHeaderPullToRefresh; // 刷新完毕
if (MJRefreshStateRefreshing == oldState) {
self.arrowImage.transform = CGAffineTransformIdentity;
// 保存刷新时间
self.lastUpdateTime = [NSDate date]; [UIView animateWithDuration:MJRefreshSlowAnimationDuration animations:^{
self.scrollView.contentInsetTop = self.scrollViewOriginalInset.top;
}];
} else {
// 执行动画
[UIView animateWithDuration:MJRefreshFastAnimationDuration animations:^{
self.arrowImage.transform = CGAffineTransformIdentity;
}];
}
break;
} case MJRefreshStatePulling: // 松开可立即刷新
{
// 设置文字
self.statusLabel.text = MJRefreshHeaderReleaseToRefresh;
// 执行动画
[UIView animateWithDuration:MJRefreshFastAnimationDuration animations:^{
self.arrowImage.transform = CGAffineTransformMakeRotation(M_PI);
}];
break;
} case MJRefreshStateRefreshing: // 正在刷新中
{
// 设置文字
self.statusLabel.text = MJRefreshHeaderRefreshing; // 执行动画
[UIView animateWithDuration:MJRefreshFastAnimationDuration animations:^{
// 1.增加滚动区域
CGFloat top = self.scrollViewOriginalInset.top + self.height;
self.scrollView.contentInsetTop = top; // 2.设置滚动位置
self.scrollView.contentOffsetY = - top;
}];
break;
} default:
break;
}
}
当然,这里面包含了contentinsettop和contentinset的各种值的含义,可以谷歌下。
2、mjfreshheader ,mjrefreshfooter分别表示下拉头和上拉尾,原理都一样,这里就拿mjrefreshheader解释。mjrefresh里面有两种添加刷新头的方式,一种是指定对象和对象函数,另一种是设置block,其实两者都一样,楼主比较习惯使用第二种,设置block。在使用
addHeaderWithCallback这个函数后,mj将这个block纪录在mj的headerblock这个成员变量里,在状态为“正在刷新”时,调用这个block。即代码:
case MJRefreshStateRefreshing:
{
// 开始转圈圈
[self.activityView startAnimating];
// 隐藏箭头
self.arrowImage.hidden = YES; // 回调
if ([self.beginRefreshingTaget respondsToSelector:self.beginRefreshingAction]) {
objc_msgSend(self.beginRefreshingTaget, self.beginRefreshingAction, self);
} if (self.beginRefreshingCallback) {
self.beginRefreshingCallback();
}
break;
}
这在父类的setstate里面操作。
mj大致原理就是这样,通过监听contentoffset并比较contentoffset的新值和旧值来判断scorllview的状态:下拉刷新,正在刷新,松开刷新等,并修改指示箭头,提示文字,在状态为正在刷新时执行相应的操作,大致就是这么个过程,作为个学习笔记,有哪些不正确的,望大家指正。
mjrefresh源码分析的更多相关文章
- ABP源码分析一:整体项目结构及目录
ABP是一套非常优秀的web应用程序架构,适合用来搭建集中式架构的web应用程序. 整个Abp的Infrastructure是以Abp这个package为核心模块(core)+15个模块(module ...
- HashMap与TreeMap源码分析
1. 引言 在红黑树--算法导论(15)中学习了红黑树的原理.本来打算自己来试着实现一下,然而在看了JDK(1.8.0)TreeMap的源码后恍然发现原来它就是利用红黑树实现的(很惭愧学了Ja ...
- nginx源码分析之网络初始化
nginx作为一个高性能的HTTP服务器,网络的处理是其核心,了解网络的初始化有助于加深对nginx网络处理的了解,本文主要通过nginx的源代码来分析其网络初始化. 从配置文件中读取初始化信息 与网 ...
- zookeeper源码分析之五服务端(集群leader)处理请求流程
leader的实现类为LeaderZooKeeperServer,它间接继承自标准ZookeeperServer.它规定了请求到达leader时需要经历的路径: PrepRequestProcesso ...
- zookeeper源码分析之四服务端(单机)处理请求流程
上文: zookeeper源码分析之一服务端启动过程 中,我们介绍了zookeeper服务器的启动过程,其中单机是ZookeeperServer启动,集群使用QuorumPeer启动,那么这次我们分析 ...
- zookeeper源码分析之三客户端发送请求流程
znode 可以被监控,包括这个目录节点中存储的数据的修改,子节点目录的变化等,一旦变化可以通知设置监控的客户端,这个功能是zookeeper对于应用最重要的特性,通过这个特性可以实现的功能包括配置的 ...
- java使用websocket,并且获取HttpSession,源码分析
转载请在页首注明作者与出处 http://www.cnblogs.com/zhuxiaojie/p/6238826.html 一:本文使用范围 此文不仅仅局限于spring boot,普通的sprin ...
- ABP源码分析二:ABP中配置的注册和初始化
一般来说,ASP.NET Web应用程序的第一个执行的方法是Global.asax下定义的Start方法.执行这个方法前HttpApplication 实例必须存在,也就是说其构造函数的执行必然是完成 ...
- ABP源码分析三:ABP Module
Abp是一种基于模块化设计的思想构建的.开发人员可以将自定义的功能以模块(module)的形式集成到ABP中.具体的功能都可以设计成一个单独的Module.Abp底层框架提供便捷的方法集成每个Modu ...
随机推荐
- IOS开发之自定义系统弹出键盘上方的view(转载)
这篇文章解决的一个开发中的实际问题就是:当弹出键盘时,自定义键盘上方的view.目前就我的经验来看,有两种解决方法.一个就是利用UITextField或者UITextView的inputAccesso ...
- C# is和as操作符
is和as操作符 is操作符:检查对象是否与给定类型兼容. 说明: 1.如果所提供的表达式非空,并且所提供的对象可以强制转换为所提供的类型而不会导致引发异常,则 is 表达式的计算结果将是 true, ...
- CMake使用教程
转自 RichardXG 原文 CMake使用教程 CMake是一个比make更高级的编译配置工具,它可以根据不同平台.不同的编译器,生成相应的Makefile或者vcproj项目. 通过编写CMak ...
- HTML5列表、块、布局
一.列表 <ol> 无序列表 (每项前有.) <ul> 有序列表 (每项前有编号1,,2,3) <li> 列表项 <ul type=" ...
- Android_ _开发技巧总结
=== 1 1.对于过多的控件,功能类似,数量又多的,可以用include方法.在实现应用中,可以把控件放入List集合中. private void initView() { // TODO ...
- YCbCr;YUV;RGB
1. 来源的差异 yuv色彩模 型来源于rgb模型,该模型的特点是将亮度和色度分离开,从而适合于图像处理领域. 应用:basic color model used in analogue color ...
- C# 连接操作MYSQL 数据库_02
using MySql.Data.MySqlclient; // 引进MYSQL 库 // C# 连接 MYSQL 数据库更好的方法 void func_02() { string str_conn_ ...
- 反人类的MyEclipse之-MyEclipse代码自动补全
如果你用过Visual Studio的自动补全功能后,再来用eclipse的自动补全功能,相信大家会有些许失望. 但是eclipse其实是非常强大的,eclipse的自动补全没有VS那么好是因为ecl ...
- AngularJs在单击提交后显示验证信息.
<!DOCTYPE html> <html ng-app="app"> <head> <meta charset="utf-8& ...
- CodeForces 593D【树链剖分】
题意: 给你n个点和n-1条边组成的一棵树,按顺序给出数的每一条边. 询问m次,每次给出一个x求x除以从点a到点b所有边的权值和的乘积,还有修改,给出边的编号,修改某条边的权值. 思路: 树链剖分,用 ...