[转载]Android Listview下拉刷新 上拉(滑动分页)加载更多 - 还是你最好 - 博客园

[转载]listview下拉刷新 上拉(滑动分页)加载更多 – 还是你最好 – 博客园.

最 近做的类似于微博的项目中,有个Android功能要使用到listview的向下拉刷新来刷新最新消息,向上拉刷新(滑动分页)来加载更多。
新浪微博就是使用这种方式的典型。
当 用户从网络上读取微博的时候,如果一下子全部加载用户未读的微博这将耗费比较长的时间,造成不好的用户体验,同时一屏的内容也不足以显示如此多的内容。这 时候,我们就需要用到另一个功能,那就是listview的分页了,其实这个分页可以做成客户端的分页,也可以做成服务器端的分页(点击加载时,从服务器 对应的加载第N页就好了!!!)。通过分页分次加载数据,用户看多少就去加载多少。
通常这也分为两种方式,一种是设置一个按钮,用户点击即加载。另一种是当用户滑动到底部时自动加载。今天我就和大家分享一下滑动到底端时自动加载这个功能的实现。
效果图如下所示:

 

下拉刷新最主要的流程是:
(1). 下拉,显示提示头部界面(HeaderView),这个过程提示用户”下拉刷新”
(2). 下拉到一定程度,超出了刷新最基本的下拉界限,我们认为达到了刷新的条件,提示用户可以”松手刷新”了,效果上允许用户继续下拉
(3). 用户松手,可能用户下拉远远不止提示头部界面,所以这一步,先反弹回仅显示提示头部界面,然后提示用户”正在加载”。
(4). 加载完成后,隐藏提示头部界面。

那么让我们看看怎么才能实现呢???
第一步:既然是要显示listview ,那么就应该有个listview 的容器pulldown.xml

<!--?xml version="1.0" encoding="utf-8"?-->

第二步:自定义一个listview中显示的item对象pulldown_item.xml

<!--?xml version="1.0" encoding="utf-8"?-->

第三步:定义一个header的xml布局文件pulldown_header.xml

<!--?xml version="1.0" encoding="utf-8"?-->

&nbsp;

&nbsp;

&nbsp;

&nbsp;

&nbsp;

第四步:如果需要向上拉更新更多的话,那就定义一个底部的footer的布局文件,在此为方便起见,只定义一个progressbar跟textview,更加复杂的显示,就交给你们了~~~~~pulldown_footer.xml:

<!--?xml version="1.0" encoding="utf-8"?-->

&nbsp;

&nbsp;

第五步:那么主要的文件这才登场:::::::重写listview这个文件主要任务是提供触摸的事件的处理方法。

/**
*

一个可以监听ListView是否滚动到最顶部或最底部的自定义控件

* 只能监听由触摸产生的,如果是ListView本身Flying导致的,则不能监听
* 如果加以改进,可以实现监听scroll滚动的具体位置等
*/

public class ScrollOverListView extends ListView {

private int mLastY;
private int mTopPosition;
private int mBottomPosition;

public ScrollOverListView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
init();
}

public ScrollOverListView(Context context, AttributeSet attrs) {
super(context, attrs);
init();
}

public ScrollOverListView(Context context) {
super(context);
init();
}

private void init(){
mTopPosition = 0;
mBottomPosition = 0;
}

@Override
public boolean onTouchEvent(MotionEvent ev) {
final int action = ev.getAction();
final int y = (int) ev.getRawY();

switch(action){
case MotionEvent.ACTION_DOWN:{
mLastY = y;
final boolean isHandled = mOnScrollOverListener.onMotionDown(ev);
if (isHandled) {
mLastY = y;
return isHandled;
}
break;
}

case MotionEvent.ACTION_MOVE:{
final int childCount = getChildCount();
if(childCount == 0) return super.onTouchEvent(ev);

final int itemCount = getAdapter().getCount() - mBottomPosition;

final int deltaY = y - mLastY;
//DLog.d("lastY=%d y=%d", mLastY, y);

final int firstTop = getChildAt(0).getTop();
final int listPadding = getListPaddingTop();

final int lastBottom = getChildAt(childCount - 1).getBottom();
final int end = getHeight() - getPaddingBottom();

final int firstVisiblePosition = getFirstVisiblePosition();

final boolean isHandleMotionMove = mOnScrollOverListener.onMotionMove(ev, deltaY);

if(isHandleMotionMove){
mLastY = y;
return true;
}

//DLog.d("firstVisiblePosition=%d firstTop=%d listPaddingTop=%d deltaY=%d", firstVisiblePosition, firstTop, listPadding, deltaY);
if (firstVisiblePosition &lt;= mTopPosition &amp;&amp; firstTop &gt;= listPadding &amp;&amp; deltaY &gt; 0) {
final boolean isHandleOnListViewTopAndPullDown;
isHandleOnListViewTopAndPullDown = mOnScrollOverListener.onListViewTopAndPullDown(deltaY);
if(isHandleOnListViewTopAndPullDown){
mLastY = y;
return true;
}
}

// DLog.d("lastBottom=%d end=%d deltaY=%d", lastBottom, end, deltaY);
if (firstVisiblePosition + childCount &gt;= itemCount &amp;&amp; lastBottom &lt;= end &amp;&amp; deltaY &lt; 0) {
final boolean isHandleOnListViewBottomAndPullDown;
isHandleOnListViewBottomAndPullDown = mOnScrollOverListener.onListViewBottomAndPullUp(deltaY);
if(isHandleOnListViewBottomAndPullDown){
mLastY = y;
return true;
}
}
break;
}

case MotionEvent.ACTION_UP:{
final boolean isHandlerMotionUp = mOnScrollOverListener.onMotionUp(ev);
if (isHandlerMotionUp) {
mLastY = y;
return true;
}
break;
}
}

mLastY = y;
return super.onTouchEvent(ev);
}

/**空的*/
private OnScrollOverListener mOnScrollOverListener = new OnScrollOverListener(){

@Override
public boolean onListViewTopAndPullDown(int delta) {
return false;
}

@Override
public boolean onListViewBottomAndPullUp(int delta) {
return false;
}

@Override
public boolean onMotionDown(MotionEvent ev) {
return false;
}

@Override
public boolean onMotionMove(MotionEvent ev, int delta) {
return false;
}

@Override
public boolean onMotionUp(MotionEvent ev) {
return false;
}

};

// =============================== public method ===============================

/**
* 可以自定义其中一个条目为头部,头部触发的事件将以这个为准,默认为第一个
*
* @param index 正数第几个,必须在条目数范围之内
*/
public void setTopPosition(int index){
if(getAdapter() == null)
throw new NullPointerException("You must set adapter before setTopPosition!");
if(index &lt; 0) throw new IllegalArgumentException("Top position must &gt; 0");

mTopPosition = index;
}

/**
* 可以自定义其中一个条目为尾部,尾部触发的事件将以这个为准,默认为最后一个
*
* @param index 倒数第几个,必须在条目数范围之内
*/
public void setBottomPosition(int index){
if(getAdapter() == null)
throw new NullPointerException("You must set adapter before setBottonPosition!");
if(index &lt; 0) throw new IllegalArgumentException("Bottom position must &gt; 0");

mBottomPosition = index;
}

/**
* 设置这个Listener可以监听是否到达顶端,或者是否到达低端等事件
*
* @see OnScrollOverListener
*/
public void setOnScrollOverListener(OnScrollOverListener onScrollOverListener){
mOnScrollOverListener = onScrollOverListener;
}

/**
* 滚动监听接口
* @see ScrollOverListView#setOnScrollOverListener(OnScrollOverListener)
*
*/
public interface OnScrollOverListener {

/**
* 到达最顶部触发
*
* @param delta 手指点击移动产生的偏移量
* @return
*/
boolean onListViewTopAndPullDown(int delta);

/**
* 到达最底部触发
*
* @param delta 手指点击移动产生的偏移量
* @return
*/
boolean onListViewBottomAndPullUp(int delta);

/**
* 手指触摸按下触发,相当于{@link MotionEvent#ACTION_DOWN}
*
* @return 返回true表示自己处理
* @see View#onTouchEvent(MotionEvent)
*/
boolean onMotionDown(MotionEvent ev);

/**
* 手指触摸移动触发,相当于{@link MotionEvent#ACTION_MOVE}
*
* @return 返回true表示自己处理
* @see View#onTouchEvent(MotionEvent)
*/
boolean onMotionMove(MotionEvent ev, int delta);

/**
* 手指触摸后提起触发,相当于{@link MotionEvent#ACTION_UP}
*
* @return 返回true表示自己处理
* @see View#onTouchEvent(MotionEvent)
*/
boolean onMotionUp(MotionEvent ev);

}

}

第六步:下拉刷新控件,真正实现下拉刷新的是这个控件,而上面的那个ScrollOverListView只是提供触摸的事件等

/**
* 下拉刷新控件
* 真正实现下拉刷新的是这个控件,
* ScrollOverListView只是提供触摸的事件等
*/
public class PullDownView extends LinearLayout implements OnScrollOverListener{
private static final String TAG = "PullDownView";

private static final int START_PULL_DEVIATION = 50; // 移动误差
private static final int AUTO_INCREMENTAL = 10; // 自增量,用于回弹

private static final int WHAT_DID_LOAD_DATA = 1; // Handler what 数据加载完毕
private static final int WHAT_ON_REFRESH = 2; // Handler what 刷新中
private static final int WHAT_DID_REFRESH = 3; // Handler what 已经刷新完
private static final int WHAT_SET_HEADER_HEIGHT = 4;// Handler what 设置高度
private static final int WHAT_DID_MORE = 5; // Handler what 已经获取完更多

private static final int DEFAULT_HEADER_VIEW_HEIGHT = 105; // 头部文件原本的高度

private static SimpleDateFormat dateFormat = new SimpleDateFormat("MM-dd HH:mm");

private View mHeaderView;
private LayoutParams mHeaderViewParams;
private TextView mHeaderViewDateView;
private TextView mHeaderTextView;
private ImageView mHeaderArrowView;
private View mHeaderLoadingView;
private View mFooterView;
private TextView mFooterTextView;
private View mFooterLoadingView;
private ScrollOverListView mListView;

private OnPullDownListener mOnPullDownListener;
private RotateAnimation mRotateOTo180Animation;
private RotateAnimation mRotate180To0Animation;

private int mHeaderIncremental; // 增量
private float mMotionDownLastY; // 按下时候的Y轴坐标

private boolean mIsDown; // 是否按下
private boolean mIsRefreshing; // 是否下拉刷新中
private boolean mIsFetchMoreing; // 是否获取更多中
private boolean mIsPullUpDone; // 是否回推完成
private boolean mEnableAutoFetchMore; // 是否允许自动获取更多

// 头部文件的状态
private static final int HEADER_VIEW_STATE_IDLE = 0; // 空闲
private static final int HEADER_VIEW_STATE_NOT_OVER_HEIGHT = 1; // 没有超过默认高度
private static final int HEADER_VIEW_STATE_OVER_HEIGHT = 2; // 超过默认高度
private int mHeaderViewState = HEADER_VIEW_STATE_IDLE;

public PullDownView(Context context, AttributeSet attrs) {
super(context, attrs);
initHeaderViewAndFooterViewAndListView(context);
}

public PullDownView(Context context) {
super(context);
initHeaderViewAndFooterViewAndListView(context);
}

/*
* ==================================
* Public method
* 外部使用,具体就是用这几个就可以了
*
* ==================================
*/

/**
* 刷新事件接口
*/
public interface OnPullDownListener {
void onRefresh();
void onMore();
}

/**
* 通知加载完了数据,要放在Adapter.notifyDataSetChanged后面
* 当你加载完数据的时候,调用这个notifyDidLoad()
* 才会隐藏头部,并初始化数据等
*/
public void notifyDidLoad() {
mUIHandler.sendEmptyMessage(WHAT_DID_LOAD_DATA);
}

/**
* 通知已经刷新完了,要放在Adapter.notifyDataSetChanged后面
* 当你执行完刷新任务之后,调用这个notifyDidRefresh()
* 才会隐藏掉头部文件等操作
*/
public void notifyDidRefresh() {
mUIHandler.sendEmptyMessage(WHAT_DID_REFRESH);
}

/**
* 通知已经获取完更多了,要放在Adapter.notifyDataSetChanged后面
* 当你执行完更多任务之后,调用这个notyfyDidMore()
* 才会隐藏加载圈等操作
*/
public void notifyDidMore() {
mUIHandler.sendEmptyMessage(WHAT_DID_MORE);
}

/**
* 设置监听器
* @param listener
*/
public void setOnPullDownListener(OnPullDownListener listener){
mOnPullDownListener = listener;
}

/**
* 获取内嵌的listview
* @return ScrollOverListView
*/
public ListView getListView(){
return mListView;
}

/**
* 是否开启自动获取更多
* 自动获取更多,将会隐藏footer,并在到达底部的时候自动刷新
* @param index 倒数第几个触发
*/
public void enableAutoFetchMore(boolean enable, int index){
if(enable){
mListView.setBottomPosition(index);
mFooterLoadingView.setVisibility(View.VISIBLE);
}else{
mFooterTextView.setText("更多");
mFooterLoadingView.setVisibility(View.GONE);
}
mEnableAutoFetchMore = enable;
}

/*
* ==================================
* Private method
* 具体实现下拉刷新等操作
*
* ==================================
*/

/**
* 初始化界面
*/
private void initHeaderViewAndFooterViewAndListView(Context context){
setOrientation(LinearLayout.VERTICAL);
//setDrawingCacheEnabled(false);
/*
* 自定义头部文件
* 放在这里是因为考虑到很多界面都需要使用
* 如果要修改,和它相关的设置都要更改
*/
mHeaderView = LayoutInflater.from(context).inflate(R.layout.pulldown_header, null);
mHeaderViewParams = new LayoutParams(LayoutParams.FILL_PARENT, LayoutParams.WRAP_CONTENT);
addView(mHeaderView, 0, mHeaderViewParams);

mHeaderTextView = (TextView) mHeaderView.findViewById(R.id.pulldown_header_text);
mHeaderArrowView = (ImageView) mHeaderView.findViewById(R.id.pulldown_header_arrow);
mHeaderLoadingView = mHeaderView.findViewById(R.id.pulldown_header_loading);

// 注意,图片旋转之后,再执行旋转,坐标会重新开始计算
mRotateOTo180Animation = new RotateAnimation(0, 180,
Animation.RELATIVE_TO_SELF, 0.5f,
Animation.RELATIVE_TO_SELF, 0.5f);
mRotateOTo180Animation.setDuration(250);
mRotateOTo180Animation.setFillAfter(true);

mRotate180To0Animation = new RotateAnimation(180, 0,
Animation.RELATIVE_TO_SELF, 0.5f,
Animation.RELATIVE_TO_SELF, 0.5f);
mRotate180To0Animation.setDuration(250);
mRotate180To0Animation.setFillAfter(true);

/**
* 自定义脚部文件
*/
mFooterView = LayoutInflater.from(context).inflate(R.layout.pulldown_footer, null);
mFooterTextView = (TextView) mFooterView.findViewById(R.id.pulldown_footer_text);
mFooterLoadingView = mFooterView.findViewById(R.id.pulldown_footer_loading);
mFooterView.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
if(!mIsFetchMoreing){
mIsFetchMoreing = true;
mFooterLoadingView.setVisibility(View.VISIBLE);
mOnPullDownListener.onMore();
}
}
});

/*
* ScrollOverListView 同样是考虑到都是使用,所以放在这里
* 同时因为,需要它的监听事件
*/
mListView = new ScrollOverListView(context);
mListView.setOnScrollOverListener(this);
mListView.setCacheColorHint(0);
addView(mListView, LayoutParams.FILL_PARENT, LayoutParams.FILL_PARENT);

// 空的listener
mOnPullDownListener = new OnPullDownListener() {
@Override
public void onRefresh() {}
@Override
public void onMore() {}
};
}

/**
* 在下拉和回推的时候检查头部文件的状态
* 如果超过了默认高度,就显示松开可以刷新,
* 否则显示下拉可以刷新
*/
private void checkHeaderViewState(){
if(mHeaderViewParams.height &gt;= DEFAULT_HEADER_VIEW_HEIGHT){
if(mHeaderViewState == HEADER_VIEW_STATE_OVER_HEIGHT) return;
mHeaderViewState = HEADER_VIEW_STATE_OVER_HEIGHT;
mHeaderTextView.setText("松开可以刷新");
mHeaderArrowView.startAnimation(mRotateOTo180Animation);
}else{
if(mHeaderViewState == HEADER_VIEW_STATE_NOT_OVER_HEIGHT
|| mHeaderViewState == HEADER_VIEW_STATE_IDLE) return;
mHeaderViewState = HEADER_VIEW_STATE_NOT_OVER_HEIGHT;
mHeaderTextView.setText("下拉可以刷新");
mHeaderArrowView.startAnimation(mRotate180To0Animation);
}
}

private void setHeaderHeight(final int height){
mHeaderIncremental = height;
mHeaderViewParams.height = height;
mHeaderView.setLayoutParams(mHeaderViewParams);
}

/**
* 自动隐藏动画
*/
class HideHeaderViewTask extends TimerTask{
@Override
public void run() {
if(mIsDown) {
cancel();
return;
}
mHeaderIncremental -= AUTO_INCREMENTAL;
if(mHeaderIncremental &gt; 0){
mUIHandler.sendEmptyMessage(WHAT_SET_HEADER_HEIGHT);
}else{
mHeaderIncremental = 0;
mUIHandler.sendEmptyMessage(WHAT_SET_HEADER_HEIGHT);
cancel();
}
}
}

/**
* 自动显示动画
*/
class ShowHeaderViewTask extends TimerTask{

@Override
public void run() {
if(mIsDown) {
cancel();
return;
}
mHeaderIncremental -= AUTO_INCREMENTAL;
if(mHeaderIncremental &gt; DEFAULT_HEADER_VIEW_HEIGHT){
mUIHandler.sendEmptyMessage(WHAT_SET_HEADER_HEIGHT);
}else{
mHeaderIncremental = DEFAULT_HEADER_VIEW_HEIGHT;
mUIHandler.sendEmptyMessage(WHAT_SET_HEADER_HEIGHT);
if(!mIsRefreshing){
mIsRefreshing = true;
mUIHandler.sendEmptyMessage(WHAT_ON_REFRESH);
}
cancel();
}
}
}

private Handler mUIHandler = new Handler(){

@Override
public void handleMessage(Message msg) {
switch (msg.what) {
case WHAT_DID_LOAD_DATA:{
mHeaderViewParams.height = 0;
mHeaderLoadingView.setVisibility(View.GONE);
mHeaderTextView.setText("下拉可以刷新");
mHeaderViewDateView = (TextView) mHeaderView.findViewById(R.id.pulldown_header_date);
mHeaderViewDateView.setVisibility(View.VISIBLE);
mHeaderViewDateView.setText("更新于:" + dateFormat.format(new Date(System.currentTimeMillis())));
mHeaderArrowView.setVisibility(View.VISIBLE);
showFooterView();
return;
}

case WHAT_ON_REFRESH:{
// 要清除掉动画,否则无法隐藏
mHeaderArrowView.clearAnimation();
mHeaderArrowView.setVisibility(View.INVISIBLE);
mHeaderLoadingView.setVisibility(View.VISIBLE);
mOnPullDownListener.onRefresh();
return;
}

case WHAT_DID_REFRESH :{
mIsRefreshing = false;
mHeaderViewState = HEADER_VIEW_STATE_IDLE;
mHeaderArrowView.setVisibility(View.VISIBLE);
mHeaderLoadingView.setVisibility(View.GONE);
mHeaderViewDateView.setText("更新于:" + dateFormat.format(new Date(System.currentTimeMillis())));
setHeaderHeight(0);
showFooterView();
return;
}

case WHAT_SET_HEADER_HEIGHT :{
setHeaderHeight(mHeaderIncremental);
return;
}

case WHAT_DID_MORE :{
mIsFetchMoreing = false;
mFooterTextView.setText("更多");
mFooterLoadingView.setVisibility(View.GONE);
}
}
}

};

/**
* 显示脚步脚部文件
*/
private void showFooterView(){
if(mListView.getFooterViewsCount() == 0 &amp;&amp; isFillScreenItem()){
mListView.addFooterView(mFooterView);
mListView.setAdapter(mListView.getAdapter());
}
}

/**
* 条目是否填满整个屏幕
*/
private boolean isFillScreenItem(){
final int firstVisiblePosition = mListView.getFirstVisiblePosition();
final int lastVisiblePostion = mListView.getLastVisiblePosition() - mListView.getFooterViewsCount();
final int visibleItemCount = lastVisiblePostion - firstVisiblePosition + 1;
final int totalItemCount = mListView.getCount() - mListView.getFooterViewsCount();

if(visibleItemCount &lt; totalItemCount) return true; return false; } /* * ================================== * 实现 OnScrollOverListener接口 * * * ================================== */ @Override public boolean onListViewTopAndPullDown(int delta) { if(mIsRefreshing || mListView.getCount() - mListView.getFooterViewsCount() == 0) return false; int absDelta = Math.abs(delta); final int i = (int) Math.ceil((double)absDelta / 2); mHeaderIncremental += i; if(mHeaderIncremental &gt;= 0){ // &amp;&amp; mIncremental &lt;= mMaxHeight
setHeaderHeight(mHeaderIncremental);
checkHeaderViewState();
}
return true;
}

@Override
public boolean onListViewBottomAndPullUp(int delta) {
if(!mEnableAutoFetchMore || mIsFetchMoreing) return false;
// 数量充满屏幕才触发
if(isFillScreenItem()){
mIsFetchMoreing = true;
mFooterTextView.setText("加载更多中...");
mFooterLoadingView.setVisibility(View.VISIBLE);
mOnPullDownListener.onMore();
return true;
}
return false;
}

@Override
public boolean onMotionDown(MotionEvent ev) {
mIsDown = true;
mIsPullUpDone = false;
mMotionDownLastY = ev.getRawY();
return false;
}

@Override
public boolean onMotionMove(MotionEvent ev, int delta) {
//当头部文件回推消失的时候,不允许滚动
if(mIsPullUpDone) return true;

// 如果开始按下到滑动距离不超过误差值,则不滑动
final int absMotionY = (int) Math.abs(ev.getRawY() - mMotionDownLastY);
if(absMotionY &lt; START_PULL_DEVIATION) return true; final int absDelta = Math.abs(delta); final int i = (int) Math.ceil((double)absDelta / 2); // onTopDown在顶部,并上回推和onTopUp相对 if(mHeaderViewParams.height &gt; 0 &amp;&amp; delta &lt; 0){ mHeaderIncremental -= i; if(mHeaderIncremental &gt; 0){
setHeaderHeight(mHeaderIncremental);
checkHeaderViewState();
}else{
mHeaderViewState = HEADER_VIEW_STATE_IDLE;
mHeaderIncremental = 0;
setHeaderHeight(mHeaderIncremental);
mIsPullUpDone = true;
}
return true;
}
return false;
}

@Override
public boolean onMotionUp(MotionEvent ev) {
mIsDown = false;
// 避免和点击事件冲突
if(mHeaderViewParams.height &gt; 0){
// 判断头文件拉动的距离与设定的高度,小了就隐藏,多了就固定高度
int x = mHeaderIncremental - DEFAULT_HEADER_VIEW_HEIGHT;
Timer timer = new Timer(true);
if(x &lt; 0){
timer.scheduleAtFixedRate(new HideHeaderViewTask(), 0, 10);
}else{
timer.scheduleAtFixedRate(new ShowHeaderViewTask(), 0, 10);
}
return true;
}
return false;
}

}

第七步:这个java文件就是封装数据,然后调用上两个文件就好了。废话不多说,上代码:::::

public class PullDownActivity extends Activity implements OnPullDownListener, OnItemClickListener{

private static final int WHAT_DID_LOAD_DATA = 0;
private static final int WHAT_DID_REFRESH = 1;
private static final int WHAT_DID_MORE = 2;

private ListView mListView;
private ArrayAdapter mAdapter;

private PullDownView mPullDownView;
private List mStrings = new ArrayList();

@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.pulldown);

/*
* 1.使用PullDownView
* 2.设置OnPullDownListener
* 3.从mPullDownView里面获取ListView
*/
mPullDownView = (PullDownView) findViewById(R.id.pull_down_view);
mPullDownView.setOnPullDownListener(this);
mListView = mPullDownView.getListView();

mListView.setOnItemClickListener(this);
mAdapter = new ArrayAdapter(this, R.layout.pulldown_item, mStrings);
mListView.setAdapter(mAdapter);

mPullDownView.enableAutoFetchMore(true, 1);

loadData();
}

private void loadData(){
new Thread(new Runnable() {

@Override
public void run() {
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}
List strings = new ArrayList();
for (String body : mStringArray) {
strings.add(body);
}
Message msg = mUIHandler.obtainMessage(WHAT_DID_LOAD_DATA);
msg.obj = strings;
msg.sendToTarget();
}
}).start();
}

@Override
public void onRefresh() {
new Thread(new Runnable() {

@Override
public void run() {
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}
Message msg = mUIHandler.obtainMessage(WHAT_DID_REFRESH);
msg.obj = "After refresh " + System.currentTimeMillis();
msg.sendToTarget();
}
}).start();
}

@Override
public void onMore() {
new Thread(new Runnable() {

@Override
public void run() {
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}
Message msg = mUIHandler.obtainMessage(WHAT_DID_MORE);
msg.obj = "After more " + System.currentTimeMillis();
msg.sendToTarget();
}
}).start();
}

private Handler mUIHandler = new Handler(){

@Override
public void handleMessage(Message msg) {
switch (msg.what) {
case WHAT_DID_LOAD_DATA:{
if(msg.obj != null){
List strings = (List) msg.obj;
if(!strings.isEmpty()){
mStrings.addAll(strings);
mAdapter.notifyDataSetChanged();
}
}
// 诉它数据加载完毕;
mPullDownView.notifyDidLoad();
break;
}
case WHAT_DID_REFRESH :{
String body = (String) msg.obj;
mStrings.add(0, body);
mAdapter.notifyDataSetChanged();
// 告诉它更新完毕
mPullDownView.notifyDidRefresh();
break;
}

case WHAT_DID_MORE:{
String body = (String) msg.obj;
mStrings.add(body);
mAdapter.notifyDataSetChanged();
// 告诉它获取更多完毕
mPullDownView.notifyDidMore();
break;
}
}

}

};

@Override
public void onItemClick(AdapterView&lt;?&gt; parent, View view, int position, long id) {
Toast.makeText(this, "啊,你点中我了 " + position, Toast.LENGTH_SHORT).show();
}

// 模拟数据
private String[] mStringArray = {
"Abbaye de Belloc", "Abbaye du Mont des Cats", "Abertam", "Abondance", "Ackawi",
"Acorn", "Adelost", "Affidelice au Chablis", "Afuega'l Pitu", "Airag", "Airedale",
"Aisy Cendre", "Allgauer Emmentaler", "Alverca", "Ambert", "American Cheese"
};

}

整个程序就这么完成了,总之,可以使用前两个封装好的文件,然后,调用就好了~~~~没什么太难的地方。

 

源代码下载地址:我是传送门   我也是个传送门

http://k-beta.com/android-listview-more-refresh.html

赞(0) 打赏
分享到: 更多 (0)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

微信扫一扫打赏