ListView实现下拉刷新和上拉加载功能

时间:2021-09-23 06:25:17
  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();
}
}