ListView实现下拉刷新和上拉加载功能
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实现下拉刷新和上拉加载功能的更多相关文章
- android--------自定义控件ListView实现下拉刷新和上拉加载
开发项目过程中基本都会用到listView的下拉刷新和上滑加载更多,为了方便重写的ListView来实现下拉刷新,同时添加了上拉自动加载更多的功能. Android下拉刷新可以分为两种情况: 1.获取 ...
- listview下拉刷新和上拉加载更多的多种实现方案
listview经常结合下来刷新和上拉加载更多使用,本文总结了三种常用到的方案分别作出说明. 方案一:添加头布局和脚布局 android系统为listview提供了addfootview ...
- Android 使用PullToRefresh实现下拉刷新和上拉加载(ExpandableListView)
PullToRefresh是一套实现非常好的下拉刷新库,它支持: 1.ListView 2.ExpandableListView 3.GridView 4.WebView 等多种常用的需要刷新的Vie ...
- 使用PullToRefresh实现下拉刷新和上拉加载
使用PullToRefresh实现下拉刷新和上拉加载 分类: Android2013-12-20 15:51 78158人阅读 评论(91) 收藏 举报 Android下拉刷新上拉加载PullToRe ...
- 安卓开发笔记——关于开源组件PullToRefresh实现下拉刷新和上拉加载(一分钟搞定,超级简单)
前言 以前在实现ListView下拉刷新和上拉加载数据的时候都是去继承原生的ListView重写它的一些方法,实现起来非常繁杂,需要我们自己去给ListView定制下拉刷新和上拉加载的布局文件,然后添 ...
- Diycode开源项目 搭建可以具有下拉刷新和上拉加载的Fragment
1.效果预览 1.1.这个首页就是一个Fragment碎片,本文讲述的就是这个碎片的搭建方式. 下拉会有一个旋转的刷新圈,上拉会刷新数据. 1.2.整体结构 首先底层的是BaseFragment 然后 ...
- Android 5.X新特性之为RecyclerView添加下拉刷新和上拉加载及SwipeRefreshLayout实现原理
RecyclerView已经写过两篇文章了,分别是Android 5.X新特性之RecyclerView基本解析及无限复用 和 Android 5.X新特性之为RecyclerView添加Header ...
- iscroll.js 下拉刷新和上拉加载
html代码如下 <!DOCTYPE html> <html> <head> <meta charset="utf-8"> < ...
- IOS 开发下拉刷新和上拉加载更多
IOS 开发下拉刷新和上拉加载更多 简介 1.常用的下拉刷新的实现方式 (1)UIRefreshControl (2)EGOTTableViewrefresh (3)AH3DPullRefresh ( ...
- IOS UITableView下拉刷新和上拉加载功能的实现
在IOS开发中UITableView是非常常用的一个功能,而在使用UITableView的时候我们经常要用到下拉刷新和上拉加载的功能,今天花时间实现了简单的UITableView的下拉刷新和上拉加载功 ...
随机推荐
- 机器学习笔记-1 Linear Regression(week 1)
1.Linear Regression with One variable Linear Regression is supervised learning algorithm, Because th ...
- xmlplus 组件设计系列之九 - 树(Tree)
树形组件是一种具有层级结构的组件,广泛应用于各种场景.本章会实现一个简单的树形组件,尽管功能有限,但你可以通过扩展它来实现自己所需要的树形组件. 数据源 树形组件的数据源可以是 JSON 格式的数据对 ...
- CSS中的字体设置
五大类:serif, sans-serif, monospace, cursive, fantasy serif 衬线字体,如 Big Caslon, 宋体 sans-serif 非衬线字体,如 He ...
- highlight.js 代码高亮插件的使用
在网页使用过程中,经常会用到代码的展示.而不同颜色的代码,可以让代码看起来更直观,也更美观. 找了几个不同的插件,觉得highlight的插件比较实用,而且用起来炒鸡简单. 比如这样: 首先,我们先下 ...
- C# 创建压缩文件
在程序中对文件进行压缩解压缩是很重要的功能,不仅能减小文件的体积,还能对文件起到保护作用.如果是生成用户可以下载的文件,还可以极大的减少网络流量并提升下载速度.最近在一个 C# 项目中用到了创建压缩文 ...
- js,jQuery和DOM操作的总结(二)
jQuery的基本操作 (1)遍历键值对和数组 , , , , , ]; $.map(arr, function (ele, index) { alert(ele + '===' + index); ...
- TPshop中B2C与B2B2C的一点理解
首先来一段百度百科记录一下: B2C 是Business-to-Customer的缩写,而其中文简称为"商对客"."商对客"是电子商务的一种模式,也就是通常说的 ...
- 【挖洞经验】如何在一条UPDATE查询中实现SQL注入
直奔主题 跟往常一样,在喝完我最爱的果汁饮料之后,我会习惯性地登录我的Synack账号,然后选择一个应用来进行渗透测试,此时我的“黑客之夜”便正式开始了. 我与很多其他的安全研究人员的习惯一样,我会在 ...
- spring-boot整合dubbo:Spring-boot-dubbo-starter
为什么要写这个小工具 如果你用过Spring-boot来提供dubbo服务,相信使用中有很多"不爽"的地方.既然使用spring boot,那么能用注解的地方绝不用xml配置,这才 ...
- ZooKeeper实践:(1)配置管理
一. 前言 配置是每个程序不可或缺的一部分,配置有多重方式:xml.ini.property.database等等,从最初的单机环境到现在的分布式环境. 1. 以文件的格式存储配置,修改任何都 ...