Android程序开发之Listview下拉刷新上拉(滑动分页)加载更多

最近做的类似于微博的项目中,有个Android功能要使用到listview的向下拉刷新来刷新最新消息,向上拉刷新(滑动分页)来加载更多。

新浪微博就是使用这种方式的典型。

当用户从网络上读取微博的时候,如果一下子全部加载用户未读的微博这将耗费比较长的时间,造成不好的用户体验,同时一屏的内容也不足以显示如此多的内容。这时候,我们就需要用到另一个功能,那就是listview的分页了,其实这个分页可以做成客户端的分页,也可以做成服务器端的分页(点击加载时,从服务器对应的加载第N页就好了!!!)。通过分页分次加载数据,用户看多少就去加载多少。

通常这也分为两种方式,一种是设置一个按钮,用户点击即加载。另一种是当用户滑动到底部时自动加载。今天我就和大家分享一下滑动到底端时自动加载这个功能的实现。

效果图如下所示:

下拉刷新最主要的流程是:

(1). 下拉,显示提示头部界面(HeaderView),这个过程提示用户”下拉刷新”

(2). 下拉到一定程度,超出了刷新最基本的下拉界限,我们认为达到了刷新的条件,提示用户可以”松手刷新”了,效果上允许用户继续下拉

(3). 用户松手,可能用户下拉远远不止提示头部界面,所以这一步,先反弹回仅显示提示头部界面,然后提示用户”正在加载”。

(4). 加载完成后,隐藏提示头部界面。

那么让我们看看怎么才能实现呢???

第一步:既然是要显示listview ,那么就应该有个listview 的容器pulldown.xml

<?xml version="1.0" encoding="utf-8"?><com.solo.pulldown.PullDownView xmlns:android="http://schemas.android.com/apk/res/android"android:id="@+id/pull_down_view"android:layout_width="fill_parent"android:layout_height="fill_parent"android:background="@android:color/white"></com.solo.pulldown.PullDownView> 

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

<?xml version="1.0" encoding="utf-8"?><TextView xmlns:android="http://schemas.android.com/apk/res/android"android:id="@android:id/text1"android:layout_width="fill_parent"android:layout_height="wrap_content"android:textAppearance="?android:attr/textAppearanceLarge"android:gravity="center_vertical"android:paddingLeft="6dip"android:minHeight="?android:attr/listPreferredItemHeight"android:textColor="@android:color/black"/> 

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

<?xml version="1.0" encoding="utf-8"?><RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"android:layout_width="fill_parent"android:layout_height="wrap_content"android:paddingBottom="10dp"android:paddingTop="10dp" ><ImageViewandroid:id="@+id/pulldown_header_arrow"android:layout_width="wrap_content"android:layout_height="wrap_content"android:layout_alignParentLeft="true"android:layout_marginLeft="20dp"android:scaleType="centerCrop"android:src="@drawable/z_arrow_down"android:visibility="invisible" /><LinearLayoutandroid:layout_width="wrap_content"android:layout_height="wrap_content"android:layout_alignBottom="@+id/pulldown_header_arrow"android:layout_alignTop="@+id/pulldown_header_arrow"android:layout_centerHorizontal="true"android:gravity="center_vertical"android:orientation="vertical" ><TextViewandroid:id="@+id/pulldown_header_text"android:layout_width="wrap_content"android:layout_height="wrap_content"android:layout_gravity="center_horizontal"android:text="加载中..." /><TextViewandroid:id="@+id/pulldown_header_date"android:layout_width="wrap_content"android:layout_height="wrap_content"android:layout_gravity="center_horizontal"android:text="更新于:"android:visibility="gone" /></LinearLayout><ProgressBarandroid:id="@+id/pulldown_header_loading"style="@android:style/Widget.ProgressBar.Small.Inverse"android:layout_width="wrap_content"android:layout_height="wrap_content"android:layout_centerVertical="true"android:layout_marginLeft="20dp" /></RelativeLayout> 

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

<?xml version="1.0" encoding="utf-8"?><RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"android:layout_width="fill_parent"android:layout_height="wrap_content"android:paddingBottom="10dp"android:paddingTop="10dp" ><TextViewandroid:id="@+id/pulldown_footer_text"android:layout_width="wrap_content"android:layout_height="wrap_content"android:layout_centerInParent="true"android:text="更多"android:textSize="15dp" /><ProgressBarandroid:id="@+id/pulldown_footer_loading"style="@android:style/Widget.ProgressBar.Small.Inverse"android:layout_width="wrap_content"android:layout_height="wrap_content"android:layout_centerVertical="true"android:layout_marginLeft="20dp"android:visibility="gone" /></RelativeLayout> 

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

/*** <p>一个可以监听ListView是否滚动到最顶部或最底部的自定义控件</p>* 只能监听由触摸产生的,如果是ListView本身Flying导致的,则不能监听</br>* 如果加以改进,可以实现监听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;}@Overridepublic 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 <= mTopPosition && firstTop >= listPadding && deltaY > 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 >= itemCount && lastBottom <= end && deltaY < 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(){@Overridepublic boolean onListViewTopAndPullDown(int delta) {return false;}@Overridepublic boolean onListViewBottomAndPullUp(int delta) {return false;}@Overridepublic boolean onMotionDown(MotionEvent ev) {return false;}@Overridepublic boolean onMotionMove(MotionEvent ev, int delta) {return false;}@Overridepublic 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 < 0)throw new IllegalArgumentException("Top position must > 0");mTopPosition = index;}/*** 可以自定义其中一个条目为尾部,尾部触发的事件将以这个为准,默认为最后一个** @param index 倒数第几个,必须在条目数范围之内*/public void setBottomPosition(int index){if(getAdapter() == null)throw new NullPointerException("You must set adapter before setBottonPosition!");if(index < 0)throw new IllegalArgumentException("Bottom position must > 0");mBottomPosition = index;}/*** 设置这个Listener可以监听是否到达顶端,或者是否到达低端等事件</br>** @see OnScrollOverListener*/public void setOnScrollOverListener(OnScrollOverListener onScrollOverListener){mOnScrollOverListener = onScrollOverListener;}/*** 滚动监听接口</br>* @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只是提供触摸的事件等

/*** 下拉刷新控件</br>* 真正实现下拉刷新的是这个控件,* 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() {@Overridepublic 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);// 空的listenermOnPullDownListener = new OnPullDownListener() {@Overridepublic void onRefresh() {}@Overridepublic void onMore() {}};}/*** 在下拉和回推的时候检查头部文件的状态</br>* 如果超过了默认高度,就显示松开可以刷新,* 否则显示下拉可以刷新*/private void checkHeaderViewState(){if(mHeaderViewParams.height >= 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{@Overridepublic void run() {if(mIsDown) {cancel();return;}mHeaderIncremental -= AUTO_INCREMENTAL;if(mHeaderIncremental > 0){mUIHandler.sendEmptyMessage(WHAT_SET_HEADER_HEIGHT);}else{mHeaderIncremental = 0;mUIHandler.sendEmptyMessage(WHAT_SET_HEADER_HEIGHT);cancel();}}}/*** 自动显示动画*/class ShowHeaderViewTask extends TimerTask{@Overridepublic void run() {if(mIsDown) {cancel();return;}mHeaderIncremental -= AUTO_INCREMENTAL;if(mHeaderIncremental > 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(){@Overridepublic 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 && 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 < totalItemCount) return true;return false;}/** ==================================* 实现 OnScrollOverListener接口*** ==================================*/@Overridepublic 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 >= 0){ // && mIncremental <= mMaxHeightsetHeaderHeight(mHeaderIncremental);checkHeaderViewState();}return true;}@Overridepublic 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;}@Overridepublic boolean onMotionDown(MotionEvent ev) {mIsDown = true;mIsPullUpDone = false;mMotionDownLastY = ev.getRawY();return false;}@Overridepublic boolean onMotionMove(MotionEvent ev, int delta) {//当头部文件回推消失的时候,不允许滚动if(mIsPullUpDone) return true;// 如果开始按下到滑动距离不超过误差值,则不滑动final int absMotionY = (int) Math.abs(ev.getRawY() - mMotionDownLastY);if(absMotionY < 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 > 0 && delta < 0){mHeaderIncremental -= i;if(mHeaderIncremental > 0){setHeaderHeight(mHeaderIncremental);checkHeaderViewState();}else{mHeaderViewState = HEADER_VIEW_STATE_IDLE;mHeaderIncremental = 0;setHeaderHeight(mHeaderIncremental);mIsPullUpDone = true;}return true;}return false;}@Overridepublic boolean onMotionUp(MotionEvent ev) {mIsDown = false;// 避免和点击事件冲突if(mHeaderViewParams.height > 0){// 判断头文件拉动的距离与设定的高度,小了就隐藏,多了就固定高度int x = mHeaderIncremental - DEFAULT_HEADER_VIEW_HEIGHT;Timer timer = new Timer(true);if(x < 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<String> mAdapter;private PullDownView mPullDownView;private List<String> mStrings = new ArrayList<String>();@Overrideprotected 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<String>(this, R.layout.pulldown_item, mStrings);mListView.setAdapter(mAdapter);mPullDownView.enableAutoFetchMore(true, 1);loadData();}private void loadData(){new Thread(new Runnable() {@Overridepublic void run() {try {Thread.sleep(2000);} catch (InterruptedException e) {e.printStackTrace();}List<String> strings = new ArrayList<String>();for (String body : mStringArray) {strings.add(body);}Message msg = mUIHandler.obtainMessage(WHAT_DID_LOAD_DATA);msg.obj = strings;msg.sendToTarget();}}).start();}@Overridepublic void onRefresh() {new Thread(new Runnable() {@Overridepublic 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();}@Overridepublic void onMore() {new Thread(new Runnable() {@Overridepublic 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(){@Overridepublic void handleMessage(Message msg) {switch (msg.what) {case WHAT_DID_LOAD_DATA:{if(msg.obj != null){List<String> strings = (List<String>) 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;}}}};@Overridepublic void onItemClick(AdapterView<?> 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"};} 

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

以上所述是小编给大家介绍的Android程序开发之Listview下拉刷新上拉(滑动分页)加载更多,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对网站的支持!

烦恼忧愁不用追,吃点好的别嫌贵,

Android程序开发之Listview下拉刷新上拉(滑动分页)加载更多

相关文章:

你感兴趣的文章:

标签云: