1 public class RefreshListView extends ListView implements OnScrollListener {

 private View mHeaderView;//头布局
private View mFooterView;//脚布局
private ImageView mArrowView;//刷新箭头
private ProgressBar mProgressBar;//进度条
private TextView mTitle;//显示的刷新状态标题
private TextView mLastRefreshTime;//上一次刷新的时间
private RotateAnimation mRotateUpAnim;//向上旋转的动画
private RotateAnimation mRotateDownAnim;//向下旋转的动画
private float startY;//按下的起始y坐标
private int mFirstVisiblePos;//记录第一个可见的item位置
private int mHeaderViewHeight;//头布局测量所得的高度
private int mFooterViewHeight;//脚布局测量所得的高度
private static final int PULL_TO_REFRESH = 0;//下拉刷新
private static final int RELEASE_TO_REFRESH = 1;//释放刷新
private static final int RELEASING = 2;//正在刷新
private int mCurrentState = PULL_TO_REFRESH;//记录当前的刷新状态
private boolean isLoadingMore;//记录上拉加载的状态
private OnRefreshListener mOnRefreshListener;//下拉刷新接口
private OnLoadMoreListener mOnLoadMoreListener;//上拉加载接口 public RefreshListView(Context context) {
super(context);
init(); } public RefreshListView(Context context, AttributeSet attrs) {
super(context, attrs);
init();
} public RefreshListView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
init();
} private void initHeaderView() {
//初始化相关布局控件
mHeaderView = View.inflate(getContext(), R.layout.layout_header_list, null);
mArrowView = (ImageView) mHeaderView.findViewById(R.id.iv_arrow);
mProgressBar = (ProgressBar) mHeaderView.findViewById(R.id.pb);
mTitle = (TextView) mHeaderView.findViewById(R.id.tv_title);
mLastRefreshTime = (TextView) mHeaderView.findViewById(R.id.tv_desc_last_refresh);
mLastRefreshTime.setText(getLastRefreshTime());
//提前手动测量,获取mHeaderView的实际高度
mHeaderView.measure(0, 0); //获取测量的高度
mHeaderViewHeight = mHeaderView.getMeasuredHeight();
//通过设置padding隐藏头布局
mHeaderView.setPadding(0, -mHeaderViewHeight, 0, 0);
//将头布局增加到ListView中,注意这里必须在setAdapter之前
this.addHeaderView(mHeaderView);
} /**
* 初始化操作
*/
private void init() {
initHeaderView();
initFooterView();
initAnimation();
//设置滑动监听
this.setOnScrollListener(this);
} private void initFooterView() {
//原理和上面添加头布局一样,不做解释了
mFooterView = View.inflate(getContext(), R.layout.layout_footer_list, null);
mFooterView.measure(0, 0);
mFooterViewHeight = mFooterView.getMeasuredHeight();
mFooterView.setPadding(0, -mFooterViewHeight, 0, 0);
this.addFooterView(mFooterView);
} /**
* 初始化下拉刷新的时候,左边箭头的执行动画
*/
private void initAnimation() {
// 向上旋转,围绕自己的中心逆时针旋转180度
mRotateUpAnim = new RotateAnimation(0f, -180f, Animation.RELATIVE_TO_SELF, 0.5f,
Animation.RELATIVE_TO_SELF, 0.5f);
mRotateUpAnim.setDuration(3000);//设置动画持续的时间
mRotateUpAnim.setFillAfter(true);//设置动画结束停留在结束的位置
// 向下旋转,围绕自己的中心逆时针旋转180度
mRotateDownAnim = new RotateAnimation(-180f, -360f, Animation.RELATIVE_TO_SELF,
0.5f, Animation.RELATIVE_TO_SELF, 0.5f);
mRotateDownAnim.setDuration(3000);
mRotateDownAnim.setFillAfter(true); } /**
* 重写ListView的onTouchEvent方法,处理我们的滑动事件
*/
@Override
public boolean onTouchEvent(MotionEvent ev) {
switch (ev.getAction()) {
case MotionEvent.ACTION_DOWN:
//记录下x坐标
startY = ev.getY();
break;
case MotionEvent.ACTION_MOVE:
//记录下滑动时的y坐标
float endY = ev.getY();
//如果当前已经是正在刷新的状态或者正在加载更多的状态,不做处理
if (mCurrentState == RELEASING || isLoadingMore) {
return super.onTouchEvent(ev);//执行父类的逻辑,我们这边不进行处理
}
//滑动的距离
float dy = endY - startY;
//第一个可见item的position是0.且滑动距离大于0,慢慢显示头布局
if (dy > 0 && mFirstVisiblePos == 0) {
//更新头布局的padding。 topPadding=(-自身高度+滑动的距离)
int paddingTop = (int) (dy - mHeaderViewHeight);
mHeaderView.setPadding(0, paddingTop, 0, 0);
//头布局已经完全显示,并且当前的状态不是释放刷新,切换
if (paddingTop > 0 && mCurrentState != RELEASE_TO_REFRESH) {
mCurrentState = RELEASE_TO_REFRESH;
updateHeaderView();
} else if (paddingTop < 0 && mCurrentState != PULL_TO_REFRESH) {
//头布局没有完全显示,并且现在不是下拉刷新的状态
mCurrentState = PULL_TO_REFRESH;
updateHeaderView(); }
return true;//事件已经被我们消费处理
} break;
case MotionEvent.ACTION_UP:
//抬起,根据当前的状态
if (mCurrentState == PULL_TO_REFRESH) {
//头布局没有完全显示,则恢复原样
mHeaderView.setPadding(0, -mHeaderViewHeight, 0, 0);
} else if (mCurrentState == RELEASE_TO_REFRESH) {
//释放刷新,头布局完全显示了
mHeaderView.setPadding(0, 0, 0, 0);
mCurrentState = RELEASING;//正在刷新中
updateHeaderView();
}
break;
default:
break;
}
return super.onTouchEvent(ev);
} /**
* 更新头布局.根据状态值来切换
*/
private void updateHeaderView() {
switch (mCurrentState) {
case PULL_TO_REFRESH://切换成下拉刷新
mTitle.setText("下拉刷新");
mArrowView.startAnimation(mRotateDownAnim);
break;
case RELEASE_TO_REFRESH://切换成释放刷新
mTitle.setText("释放刷新");
mArrowView.startAnimation(mRotateUpAnim);
break;
case RELEASING://切换成正在刷新
mArrowView.clearAnimation();//这里要清除动画
mArrowView.setVisibility(INVISIBLE);
mProgressBar.setVisibility(VISIBLE);
mTitle.setText("正在刷新中");
//回调刷新接口方法进行刷新
if (mOnRefreshListener != null) {
mOnRefreshListener.onRefresh();
}
break;
default:
break;
}
} /**
* 刷新完成
*/
public void onRefreshComplete() {
//还原最初的状态
mCurrentState = PULL_TO_REFRESH;
mHeaderView.setPadding(0, -mHeaderViewHeight, 0, 0);
mArrowView.setVisibility(VISIBLE);
mProgressBar.setVisibility(INVISIBLE);
String lastRefreshTime = getLastRefreshTime();
mLastRefreshTime.setText(lastRefreshTime);
} /**
* 上拉加载完成
*/
public void onLoadMoreComplete() {
//还原最初的状态
isLoadingMore = false;
mFooterView.setPadding(0, 0, 0, 0);
} /**
* 获取上一次刷新的时间
*/
private String getLastRefreshTime() {
SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
return format.format(new Date());
} /**
* 对外暴露设置刷新接口的方法
*/
public void setOnRefreshListener(OnRefreshListener mOnRefreshListener) {
this.mOnRefreshListener = mOnRefreshListener;
} public void setOnLoadMoreListener(OnLoadMoreListener mOnLoadMoreListener) {
this.mOnLoadMoreListener = mOnLoadMoreListener;
} /**
* 滑动状态改变
*/
@Override
public void onScrollStateChanged(AbsListView view, int scrollState) {
if (isLoadingMore || mCurrentState == RELEASING) {
//正在加载更多,或者刷新状态。不做处理
return;
}
if (scrollState == SCROLL_STATE_IDLE && getLastVisiblePosition() == getCount() - 1) {
//空闲状态且到了最后一个item,执行上拉加载
isLoadingMore = true;
mFooterView.setPadding(0, 0, 0, 0); setSelection(getCount() - 1);//跳转到最后一条使其显示加载更多
if (mOnLoadMoreListener != null) {
mOnLoadMoreListener.onLoadMore();
}
} } /**
* 滑动过程
*/
@Override
public void onScroll(AbsListView view, int firstVisibleItem, int visibleItemCount,
int totalItemCount) {
//记录第一个可见item的position
mFirstVisiblePos = firstVisibleItem;
} /**
* 刷新接口
*/
public interface OnRefreshListener { void onRefresh();
} /**
* 加载更多接口
*/
public interface OnLoadMoreListener { void onLoadMore();
}
}

ListView实现下拉刷新和上拉加载功能的更多相关文章

  1. android--------自定义控件ListView实现下拉刷新和上拉加载

    开发项目过程中基本都会用到listView的下拉刷新和上滑加载更多,为了方便重写的ListView来实现下拉刷新,同时添加了上拉自动加载更多的功能. Android下拉刷新可以分为两种情况: 1.获取 ...

  2. listview下拉刷新和上拉加载更多的多种实现方案

    listview经常结合下来刷新和上拉加载更多使用,本文总结了三种常用到的方案分别作出说明. 方案一:添加头布局和脚布局        android系统为listview提供了addfootview ...

  3. Android 使用PullToRefresh实现下拉刷新和上拉加载(ExpandableListView)

    PullToRefresh是一套实现非常好的下拉刷新库,它支持: 1.ListView 2.ExpandableListView 3.GridView 4.WebView 等多种常用的需要刷新的Vie ...

  4. 使用PullToRefresh实现下拉刷新和上拉加载

    使用PullToRefresh实现下拉刷新和上拉加载 分类: Android2013-12-20 15:51 78158人阅读 评论(91) 收藏 举报 Android下拉刷新上拉加载PullToRe ...

  5. 安卓开发笔记——关于开源组件PullToRefresh实现下拉刷新和上拉加载(一分钟搞定,超级简单)

    前言 以前在实现ListView下拉刷新和上拉加载数据的时候都是去继承原生的ListView重写它的一些方法,实现起来非常繁杂,需要我们自己去给ListView定制下拉刷新和上拉加载的布局文件,然后添 ...

  6. Diycode开源项目 搭建可以具有下拉刷新和上拉加载的Fragment

    1.效果预览 1.1.这个首页就是一个Fragment碎片,本文讲述的就是这个碎片的搭建方式. 下拉会有一个旋转的刷新圈,上拉会刷新数据. 1.2.整体结构 首先底层的是BaseFragment 然后 ...

  7. Android 5.X新特性之为RecyclerView添加下拉刷新和上拉加载及SwipeRefreshLayout实现原理

    RecyclerView已经写过两篇文章了,分别是Android 5.X新特性之RecyclerView基本解析及无限复用 和 Android 5.X新特性之为RecyclerView添加Header ...

  8. iscroll.js 下拉刷新和上拉加载

    html代码如下 <!DOCTYPE html> <html> <head> <meta charset="utf-8"> < ...

  9. IOS 开发下拉刷新和上拉加载更多

    IOS 开发下拉刷新和上拉加载更多 简介 1.常用的下拉刷新的实现方式 (1)UIRefreshControl (2)EGOTTableViewrefresh (3)AH3DPullRefresh ( ...

  10. IOS UITableView下拉刷新和上拉加载功能的实现

    在IOS开发中UITableView是非常常用的一个功能,而在使用UITableView的时候我们经常要用到下拉刷新和上拉加载的功能,今天花时间实现了简单的UITableView的下拉刷新和上拉加载功 ...

随机推荐

  1. OpenMP 入门教程

    前两天(其实是几个月以前了)看到了代码中有 #pragma omp parallel for 一段,感觉好像是 OpenMP,以前看到并行化的东西都是直接躲开,既然躲不开了,不妨研究一下: OpenM ...

  2. php 中时间函数date及常用的时间计算

    曾在项目中需要使用到今天,昨天,本周,本月,本季度,今年,上周上月,上季度等等时间戳,趁最近时间比较充足,因此计划对php的相关时间知识点进行总结学习 1,阅读php手册date函数 常用时间函数: ...

  3. HttpClient--HttpGet使用

    最近公司在做一个爬虫工具,爬取公司现网的数据,留给方通项目使用 用到里阿帕奇的这两个类,在网上看到了一些资料结合自己的应用,这个贴出一个demo import com.alibaba.fastjson ...

  4. bash Shell条件测试

    3种测试命令: test EXPRESSION [ EXPRESSION ] [[ EXPRESSION ]]  注意:EXPRESSION前后必须有空白字符 bash的测试类型 数值测试: -eq: ...

  5. 关于删除数组中重复元素的lintcode代码

    时间自由度为o(n),空间自由度为o(1); class Solution {public:    /**     * @param A: a list of integers     * @retu ...

  6. 关于for循环的几种经典案例

    由于for循环可以通过控制循环变量的初始值和循环结束条件来改变遍历的区间,所以在排序或者遍历的时候,利用for循环就比较简单,以下是本人学习后得到的一些总结案例. 1.排序的应用 1)交换排序:通过取 ...

  7. 使用Nginx实现Tomcat集群负载均衡

    概述 要解决的问题 环境准备以及问题解决思路 配置 测试 小结 一.概述 使用Nginx主要是来解决高并发情况下的负载均衡问题. 二.要解决的问题 1.最主要是负载均衡请求分发. 2.文件上传功能,只 ...

  8. javaweb之监听器详解

    在servlet中定义了多种类型的监听器,他们用于监听事件源分别是servletContext,httpsession,servletrequest 这三个域对象. servlet中监听器主要有三类: ...

  9. 为Play初学者准备的Scala基础知识

    1 前言 本文的主要目的是为了让Play Framework的初学者快速了解Scala语言,算是一篇Play Framework的入门前传吧.使用PlayFramework可以极大的提高开发效率,但是 ...

  10. 配置nginx脚本开机自启动

    vi /etc/init.d/nginx 插入以下内容,修改红色字体自己安装路径 #!/bin/bash## chkconfig: - 85 15# description: Nginx is a W ...