自定义listview完成上拉刷新,下拉加载的功能,重写ontouchevent方法

来源:互联网 发布:淘宝支付不了钱怎么办 编辑:程序博客网 时间:2024/05/17 23:53

最 近做的类似于微博的项目中,有个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" >     <ImageView        android: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" />     <LinearLayout        android: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" >         <TextView            android:id="@+id/pulldown_header_text"            android:layout_width="wrap_content"            android:layout_height="wrap_content"            android:layout_gravity="center_horizontal"            android:text="加载中..." />         <TextView            android: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>     <ProgressBar        android: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" >     <TextView        android:id="@+id/pulldown_footer_text"        android:layout_width="wrap_content"        android:layout_height="wrap_content"        android:layout_centerInParent="true"        android:text="更多"        android:textSize="15dp" />     <ProgressBar        android: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;    }     @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 <= 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(){         @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 < 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() {            @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() {}        };    }     /**     * 在下拉和回推的时候检查头部文件的状态</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{        @Override        public 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{         @Override        public 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(){         @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 && 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接口     *     *     * ==================================     */     @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 >= 0){ // && mIncremental <= 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 < 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;    }     @Override    public 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>();     @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<String>(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<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();    }     @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<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;                }            }         }     };     @Override    public 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"    }; }
复制代码

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

 

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

0 0