我们知道页面的下拉刷新目前基本已经成为智能移动终端的标配刷新方式。Twitter设计出现有的下拉刷新(在2013年申请了专利)。

下拉刷新1.jpg

这一优美而又简单的刷新方式,很快使得各大系统纷纷效仿;IOS在6.0开始引入,Android由于一开始不太重视交互体验这方面,直到Android5.0开始才借鉴这样一种刷新方式。那么我们今天就来研究研究怎么实现。

目前我收集到的不同方式有以下几种:

方案一: listview headview调用setPadding的方式

方案二: listview的多种样式显示 getview 实现

方案三: SwipeRefreshLayout实现下来刷新 没有加载更多

方案四:使用PullToRefresh 实现上拉加载和下拉刷新

方案五:使用Ultra-Pull-To-Refresh实现上拉加载和下拉刷新 类似方案三没有加载更多

我们首先讲解第一种实现方式,也是我们项目当中经常用到的。

实现思路:

1、首先为ListView添加头布局和底布局,addHeadView()

2、通过改变HeaderView的paddingTop值,来控制控件的显示和隐藏

3、根据我们滑动的状态,动态修改头部布局。

listview.png

完整的刷新过程:

1、下拉刷新——2、释放刷新——3、刷新中——1、下拉刷新

也就是分3种状态,那么分别什么时候切换状态呢。看以下具体分析:

listview状态图.png

1、下拉刷新——释放刷新:

当headView的paddingTop的值从-headViewHeight减小到0时,说明此刻为释放刷新;

2、释放刷新——刷新中:

headView的paddingTop一直大于0时,此时松开手指,将headView固定在paddingTop为0的位置,此时也是刚好请求网络的时机。

3、刷新中——下拉刷新:

刷新结束,paddingTop值由0重新回到-headViewHeight

代码实现逻辑:

1、实现 OnScrollListener 接口,在 onScroll() 方法中记录当前是否到顶部或者底部;

2、重写 onTouchEvent() 方法,通过moveY - downY得到偏移量,将偏移量设置为HeadView的paddingTop,使HeadView跟随手指移动产生变化;

3、onScrollStateChanged() 方法中根据状态变化(开始滚动或停止滚动),判断是否需要加载更多。

4、定义了回调接口,让用户自己编写下拉刷新的业务代码;

完整代码:

@Override

public void onScrollStateChanged(AbsListView view, int scrollState) {

if (scrollState == OnScrollListener.SCROLL_STATE_IDLE

|| scrollState == OnScrollListener.SCROLL_STATE_FLING) {

if (isScroll2Bottom && !isLoadMoving) { // 滚动到底部

// 加载更多

if (!canLoadMore) {

return;

}

footerView.setPadding(0, 0, 0, 0);

this.setSelection(this.getCount()); // 滚动到ListView的底部

isLoadMoving = true;

//回调接口执行请求加载

if (mOnRefreshListener != null) {

mOnRefreshListener.onLoadingMore();

}

}

}

}

@Override

public void onScroll(AbsListView view, int firstVisibleItem, int visibleItemCount, int totalItemCount) {

mFirstVisibleItem = firstVisibleItem;

isScroll2Bottom = (firstVisibleItem + visibleItemCount) >= totalItemCount

&& totalItemCount > 0;

}

public boolean onTouchEvent(MotionEvent ev) {

if (isEnd) {//如果现在时结束的状态,即刷新完毕了,可以再次刷新了,在onRefreshComplete中设置

if (isRefreable) {//如果现在是可刷新状态 在setOnMeiTuanListener中设置为true

switch (ev.getAction()) {

//用户按下

case MotionEvent.ACTION_DOWN:

//如果当前是在listview顶部并且没有记录y坐标

if (mFirstVisibleItem == 0 && !isRecord) {

//将isRecord置为true,说明现在已记录y坐标

isRecord = true;

//将当前y坐标赋值给startY起始y坐标

startY = ev.getY();

}

break;

//用户滑动

case MotionEvent.ACTION_MOVE:

//再次得到y坐标,用来和startY相减来计算offsetY位移值

float tempY = ev.getY();

//再起判断一下是否为listview顶部并且没有记录y坐标

if (mFirstVisibleItem == 0 && !isRecord) {

isRecord = true;

startY = tempY;

}

//如果当前状态不是正在刷新的状态,并且已经记录了y坐标

if (state != REFRESHING && isRecord) {

//计算y的偏移量

offsetY = tempY - startY;

//如果当前的状态是放开刷新,并且已经记录y坐标

if (state == RELEASE_TO_REFRESH && isRecord) {

setSelection(0);

//如果当前滑动的距离小于headerView的总高度

if (-mHeaderViewHeight + offsetY / RATIO < 0) {

//将状态置为下拉刷新状态

state = PULL_TO_REFRESH;

//根据状态改变headerView,主要是更新动画和文字等信息

changeHeaderByState(state);

//如果当前y的位移值小于0,即为headerView隐藏了

} else if (offsetY <= 0) {

//将状态变为done

state = DONE;

//根据状态改变headerView,主要是更新动画和文字等信息

changeHeaderByState(state);

}

}

//如果当前状态为下拉刷新并且已经记录y坐标

if (state == PULL_TO_REFRESH && isRecord) {

setSelection(0);

//如果下拉距离大于等于headerView的总高度

if (-mHeaderViewHeight + offsetY / RATIO >= 0) {

//将状态变为放开刷新

state = RELEASE_TO_REFRESH;

//根据状态改变headerView,主要是更新动画和文字等信息

changeHeaderByState(state);

//如果当前y的位移值小于0,即为headerView隐藏了

} else if (offsetY <= 0) {

//将状态变为done

state = DONE;

//根据状态改变headerView,主要是更新动画和文字等信息

changeHeaderByState(state);

}

}

//如果当前状态为done并且已经记录y坐标

if (state == DONE && isRecord) {

//如果位移值大于0

if (offsetY >= 0) {

//将状态改为下拉刷新状态

state = PULL_TO_REFRESH;

}

}

//如果为下拉刷新状态

if (state == PULL_TO_REFRESH) {

//则改变headerView的padding来实现下拉的效果

headerView.setPadding(0, (int) (-mHeaderViewHeight + offsetY / RATIO), 0, 0);

}

//如果为放开刷新状态

if (state == RELEASE_TO_REFRESH) {

//改变headerView的padding值

headerView.setPadding(0, (int) (-mHeaderViewHeight + offsetY / RATIO), 0, 0);

}

}

break;

//当用户手指抬起时

case MotionEvent.ACTION_UP:

//如果当前状态为下拉刷新状态

if (state == PULL_TO_REFRESH) {

//平滑的隐藏headerView

headerView.setPadding(0, -mHeaderViewHeight, 0, 0);

//根据状态改变headerView

changeHeaderByState(state);

}

//如果当前状态为放开刷新

if (state == RELEASE_TO_REFRESH) {

//平滑的滑到正好显示headerView

headerView.setPadding(0, -mHeaderViewHeight, 0, 0);

//将当前状态设置为正在刷新

state = REFRESHING;

//回调接口的onRefresh方法

if (mOnRefreshListener != null) {

mOnRefreshListener.onRefresh();

}

//根据状态改变headerView

changeHeaderByState(state);

}

//这一套手势执行完,一定别忘了将记录y坐标的isRecord改为false,以便于下一次手势的执行

isRecord = false;

break;

}

}

}

return super.onTouchEvent(ev);

}

那么到此,我们就把下拉刷新分析完了。

android listview下拉刷新动画,ListView下拉刷新实现方式详解和改造(上)相关推荐

  1. android 实现表格横向混动_Android图文混排实现方式详解

    在使用TextView的时候,我们经常需要在TextView中进行图文混排,比如在QQ中聊天的消息中的表情,底部tab图标等. 一.场景 二.实现方式 Android官方对TextView的图文混排提 ...

  2. android 说话水波动画,Android实用View——水波动画效果多种实现方式详解

    原标题:Android实用View--水波动画效果多种实现方式详解 这次给大家带来的是一篇关于自定义View实现水波动画效果的文章,其实在去年项目中使用过类似的动画,当时就自定义View也实现了预期的 ...

  3. python2和python3分别是python的两个版本_Windows下Python2与Python3两个版本共存的方法详解...

    前言 一向用Python 3,最近研究微信公众号开发,各云平台只支持Python 2.7,想用其他版本需要自己搭建环境.而网上又搜不到Python 3开发微信公众号的资料.暂打算先使用Python 2 ...

  4. mysql gz 安装_Linux下安装mysql 5.7.17.tar.gz的教程详解

    1.创建MySQL组和mysql用户 groupadd mysql useradd -r -g mysql mysql 2.拷贝: cp -R mysql-5.7.16-linux-glibc2.5- ...

  5. Linux进程最大socket数,Linux下高并发socket最大连接数所受的各种限制(详解)

    1.修改用户进程可打开文件数限制 在Linux平台上,无论编写客户端程序还是服务端程序,在进行高并发TCP连接处理时,最高的并发数量都要受到系统对用户单一进程同时可打开文件数量的限制(这是因为系统为每 ...

  6. linux如何确定共享库路径,摘录Linux下动态共享库加载时的搜索路径详解

    对动态库的实际应用还不太熟悉的读者可能曾经遇到过类似"error while loading shared libraries"这样的错误,这是典型的因为需要的动态库不在动态链接器 ...

  7. linux修改zip中文件,Linux下修改jar、zip等文件内的文件详解

    Linux下修改jar.zip等文件内的文件详解 Linux下修改jar.zip等文件内的文件详解 看到很多同事在Linux环境下修改jar包内的文本文件或zip中的文本文件时,经常是先把jar包或z ...

  8. window10下拯救者笔记本RTX3060laptop配置CUDA11.0 pytorch版详解

    cuda版本11.0 torch=1.7.1+cu110 torchvision==0.8.2+cu110 torchaudio==0.7.2 可以直接用命令: pip install torch== ...

  9. Windows下为有道词典添加词库(图文详解)

    原文地址:LittleStarLord的博客    Windows下为有道词典添加词库(图文详解)http://blog.sina.com.cn/s/blog_6c0267490102wett.htm ...

最新文章

  1. 转载: EMD(Emprical mode decomposition)经验模态分解
  2. 如何将传统OA移动化?
  3. 树莓派安装oepncv3.43
  4. 59.进程的三种状态,以及之间转换的过程
  5. Kth Largest Element in an Array
  6. 关于STL 容器的嵌套使用, 小试牛刀
  7. oracle 11.2.0.4 mos,【翻译自mos文章】在RHEL7 or OEL7上安装oracle 11.2.0.4 db时的
  8. Mysql剖析单条查询三种方法
  9. IntelliJ IDEA for Mac在MacOS模式下的搜索/查询/查找快捷键(Search Shortcut)
  10. 免费公开课 | 强化学习及其在竞速无人机中的应用
  11. linux路由内核实现分析(二)---FIB相关数据结构(3)
  12. python可视化是什么意思_python3数据可视化是什么?
  13. java 生成随机编码_Java生成随机编码
  14. minikube addons enable ingress 启动错误
  15. 电子元器件:三极管参数笔记(持续记录)
  16. 刨根问底,5问分析法
  17. Django-admin注册model后一直404,路径都配置的正确
  18. MacOS VSCode配置c++环境
  19. 国产CPU乱战遭遇生态壁垒:英特尔工艺领先龙芯两代
  20. 网络工程师--网络规划和设计案例分析(3)

热门文章

  1. 如何修改 pdf 文件默认的显示图标
  2. SAP 电商云 Spartacus UI feature level 的一个测试
  3. jQuery.sap.registerModulePath(cus.crm.notes.ext, '/ZCRM_NOTES_W8');
  4. SAP Fiori 1.0和2.0的区别
  5. SAP UI5 debug mode
  6. Error dialog box generic entry point
  7. Cloud for Customer动态控制任意UI element的visibility
  8. another CRM inbound debug - 另一个CRM中间件的调试记录
  9. SAP BSP同本地硬件的集成
  10. CRM端 equipment hierarchy change成功的标志