转载请声明出处http://blog.csdn.net/zhongkejingwang/article/details/38963177
前一篇已经把下拉刷新和上拉加载集成到一块了并且已经对所有View通用了,但是有时候需要的加载方式不是上拉,而是像新浪微博加载评论或QQ好友动态滑到ListView的底部时就自动加载了。所以在这篇文章里再介绍这种自动加载的实现,当然了,这个功能只针对ListView。如果仅仅是实现这样的自动加载,那就太简单了,也就判断是否滚动到底部而已,代码量很少,所以还加了下拉刷新,但在这里这两个功能是独立的,自动加载只是针对ListView进行的修改。
效果图如下:
下拉刷新的原理就不讲了,可以去看 Android通用版下拉刷新上拉加载控件,实现自动加载的思路就是:
在ListView后面增加一个FooterView,时刻监听ListView的滑动状态,当FooterView被滑到可见时,执行自动加载操作。
但是这里需要注意的是手动滑到底和自由滚到底时的区别:
1、使劲滑的时候自由滚动在底部时会显示自动加载并执行加载回调
2、当用手慢慢滑动到底时,如果不松手,不会自动加载。
所以,基于这两个考虑,自然而然就需要覆写View的两个方法:onScrollChanged和onTouchEvent。
接下来就可以看代码了:
package com.jingchen.autoload; import android.content.Context; import android.graphics.drawable.AnimationDrawable; import android.util.AttributeSet; import android.view.LayoutInflater; import android.view.MotionEvent; import android.view.View; import android.widget.ImageView; import android.widget.ListView; import android.widget.TextView; /** * 如果不需要下拉刷新直接在canPullDown中返回false,这里的自动加载和下拉刷新没有冲突,通过增加在尾部的footerview实现自动加载, * 所以在使用中不要再动footerview了 * * @author chenjing * */ public class PullableListView extends ListView implements Pullable { public static final int INIT = 0; public static final int LOADING = 1; private OnLoadListener mOnLoadListener; private ImageView mLoadingView; private TextView mStateTextView; private int state = INIT; private boolean canLoad = true; private AnimationDrawable mLoadAnim; public PullableListView(Context context) { super(context); init(context); } public PullableListView(Context context, AttributeSet attrs) { super(context, attrs); init(context); } public PullableListView(Context context, AttributeSet attrs, int defStyle) { super(context, attrs, defStyle); init(context); } private void init(Context context) { View view = LayoutInflater.from(context).inflate(R.layout.load_more, null); mLoadingView = (ImageView) view.findViewById(R.id.loading_icon); mLoadingView.setBackgroundResource(R.anim.loading_anim); mLoadAnim = (AnimationDrawable) mLoadingView.getBackground(); mStateTextView = (TextView) view.findViewById(R.id.loadstate_tv); addFooterView(view, null, false); } @Override public boolean onTouchEvent(MotionEvent ev) { switch (ev.getActionMasked()) { case MotionEvent.ACTION_DOWN: // 按下的时候禁止自动加载 canLoad = false; break; case MotionEvent.ACTION_UP: // 松开手判断是否自动加载 canLoad = true; checkLoad(); break; } return super.onTouchEvent(ev); } @Override protected void onScrollChanged(int l, int t, int oldl, int oldt) { super.onScrollChanged(l, t, oldl, oldt); // 在滚动中判断是否满足自动加载条件 checkLoad(); } /** * 判断是否满足自动加载条件 */ private void checkLoad() { if (reachBottom() && mOnLoadListener != null && state != LOADING && canLoad) { mOnLoadListener.onLoad(this); changeState(LOADING); } } private void changeState(int state) { this.state = state; switch (state) { case INIT: mLoadAnim.stop(); mLoadingView.setVisibility(View.INVISIBLE); mStateTextView.setText(R.string.more); break; case LOADING: mLoadingView.setVisibility(View.VISIBLE); mLoadAnim.start(); mStateTextView.setText(R.string.loading); break; } } /** * 完成加载 */ public void finishLoading() { changeState(INIT); } @Override public boolean canPullDown() { if (getCount() == 0) { // 没有item的时候也可以下拉刷新 return true; } else if (getFirstVisiblePosition() == 0 && getChildAt(0).getTop() >= 0) { // 滑到ListView的顶部了 return true; } else return false; } public void setOnLoadListener(OnLoadListener listener) { this.mOnLoadListener = listener; } /** * @return footerview可见时返回true,否则返回false */ public boolean reachBottom() { if (getCount() == 0) { // 没有item的时候也可以上拉加载 return true; } else if (getLastVisiblePosition() == (getCount() - 1)) { // 滑到底部了 if (getChildAt(getLastVisiblePosition() - getFirstVisiblePosition()) != null && getChildAt( getLastVisiblePosition() - getFirstVisiblePosition()).getTop() < getMeasuredHeight()) return true; } return false; } public interface OnLoadListener { void onLoad(PullableListView pullableListView); } }
源码下载
http://www.it165.net/uploadfile/files/2014/0901/ListView.zip