一区二区三区日韩精品-日韩经典一区二区三区-五月激情综合丁香婷婷-欧美精品中文字幕专区

分享

listview下拉刷新 上拉(滑動分頁)加載更多

 DeepReading 2019-06-18

最 近做的類似于微博的項目中,有個Android功能要使用到listview的向下拉刷新來刷新最新消息,向上拉刷新(滑動分頁)來加載更多。
新浪微博就是使用這種方式的典型。
當(dāng)用戶從網(wǎng)絡(luò)上讀取微博的時候,如果一下子全部加載用戶未讀的微博這將耗費(fèi)比較長的時間,造成不好的用戶體驗,同時一屏的內(nèi)容也不足以顯示如此多的內(nèi)容。這時候,我們就需要用到另一個功能,那就是listview的分頁了,其實(shí)這個分頁可以做成客戶端的分頁,也可以做成服務(wù)器端的分頁(點(diǎn)擊加載時,從服務(wù)器對應(yīng)的加載第N頁就好了?。。。Mㄟ^分頁分次加載數(shù)據(jù),用戶看多少就去加載多少。
通常這也分為兩種方式,一種是設(shè)置一個按鈕,用戶點(diǎn)擊即加載。另一種是當(dāng)用戶滑動到底部時自動加載。今天我就和大家分享一下滑動到底端時自動加載這個功能的實(shí)現(xiàn)。
效果圖如下所示:

 

下拉刷新最主要的流程是:
(1). 下拉,顯示提示頭部界面(HeaderView),這個過程提示用戶”下拉刷新”
(2). 下拉到一定程度,超出了刷新最基本的下拉界限,我們認(rèn)為達(dá)到了刷新的條件,提示用戶可以”松手刷新”了,效果上允許用戶繼續(xù)下拉
(3). 用戶松手,可能用戶下拉遠(yuǎn)遠(yuǎn)不止提示頭部界面,所以這一步,先反彈回僅顯示提示頭部界面,然后提示用戶”正在加載”。
(4). 加載完成后,隱藏提示頭部界面。

那么讓我們看看怎么才能實(shí)現(xiàn)呢???
第一步:既然是要顯示listview ,那么就應(yīng)該有個listview 的容器pulldown.xml

復(fù)制代碼
<?xml version="1.0" encoding="utf-8"?>
<com.solo.pulldown.PullDownView xmlns:android="http://schemas./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>
復(fù)制代碼

第二步:自定義一個listview中顯示的item對象pulldown_item.xml

復(fù)制代碼
<?xml version="1.0" encoding="utf-8"?>
<TextView xmlns:android="http://schemas./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"
/>
復(fù)制代碼

第三步:定義一個header的xml布局文件pulldown_header.xml

復(fù)制代碼
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas./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>
復(fù)制代碼

第四步:如果需要向上拉更新更多的話,那就定義一個底部的footer的布局文件,在此為方便起見,只定義一個progressbar跟textview,更加復(fù)雜的顯示,就交給你們了~~~~~pulldown_footer.xml:

復(fù)制代碼
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas./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>
復(fù)制代碼

第五步:那么主要的文件這才登場:::::::重寫listview這個文件主要任務(wù)是提供觸摸的事件的處理方法。

復(fù)制代碼
/**
 * <p>一個可以監(jiān)聽ListView是否滾動到最頂部或最底部的自定義控件</p>
 * 只能監(jiān)聽由觸摸產(chǎn)生的,如果是ListView本身Flying導(dǎo)致的,則不能監(jiān)聽</br>
 * 如果加以改進(jìn),可以實(shí)現(xiàn)監(jiān)聽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 ===============================
 
    /**
     * 可以自定義其中一個條目為頭部,頭部觸發(fā)的事件將以這個為準(zhǔn),默認(rèn)為第一個
     *
     * @param index 正數(shù)第幾個,必須在條目數(shù)范圍之內(nèi)
     */
    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;
    }
 
    /**
     * 可以自定義其中一個條目為尾部,尾部觸發(fā)的事件將以這個為準(zhǔn),默認(rèn)為最后一個
     *
     * @param index 倒數(shù)第幾個,必須在條目數(shù)范圍之內(nèi)
     */
    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;
    }
 
    /**
     * 設(shè)置這個Listener可以監(jiān)聽是否到達(dá)頂端,或者是否到達(dá)低端等事件</br>
     *
     * @see OnScrollOverListener
     */
    public void setOnScrollOverListener(OnScrollOverListener onScrollOverListener){
        mOnScrollOverListener = onScrollOverListener;
    }
 
    /**
     * 滾動監(jiān)聽接口</br>
     * @see ScrollOverListView#setOnScrollOverListener(OnScrollOverListener)
     *
     */
    public interface OnScrollOverListener {
 
        /**
         * 到達(dá)最頂部觸發(fā)
         *
         * @param delta 手指點(diǎn)擊移動產(chǎn)生的偏移量
         * @return
         */
        boolean onListViewTopAndPullDown(int delta);
 
        /**
         * 到達(dá)最底部觸發(fā)
         *
         * @param delta 手指點(diǎn)擊移動產(chǎn)生的偏移量
         * @return
         */
        boolean onListViewBottomAndPullUp(int delta);
 
        /**
         * 手指觸摸按下觸發(fā),相當(dāng)于{@link MotionEvent#ACTION_DOWN}
         *
         * @return 返回true表示自己處理
         * @see View#onTouchEvent(MotionEvent)
         */
        boolean onMotionDown(MotionEvent ev);
 
        /**
         * 手指觸摸移動觸發(fā),相當(dāng)于{@link MotionEvent#ACTION_MOVE}
         *
         * @return 返回true表示自己處理
         * @see View#onTouchEvent(MotionEvent)
         */
        boolean onMotionMove(MotionEvent ev, int delta);
 
        /**
         * 手指觸摸后提起觸發(fā),相當(dāng)于{@link MotionEvent#ACTION_UP}
         *
         * @return 返回true表示自己處理
         * @see View#onTouchEvent(MotionEvent)
         */
        boolean onMotionUp(MotionEvent ev);
 
    }
 
}
復(fù)制代碼

第六步:下拉刷新控件,真正實(shí)現(xiàn)下拉刷新的是這個控件,而上面的那個ScrollOverListView只是提供觸摸的事件等

復(fù)制代碼
/**
 * 下拉刷新控件</br>
 * 真正實(shí)現(xiàn)下拉刷新的是這個控件,
 * 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 數(shù)據(jù)加載完畢
    private static final int WHAT_ON_REFRESH = 2;       // Handler what 刷新中
    private static final int WHAT_DID_REFRESH = 3;      // Handler what 已經(jīng)刷新完
    private static final int WHAT_SET_HEADER_HEIGHT = 4;// Handler what 設(shè)置高度
    private static final int WHAT_DID_MORE = 5;         // Handler what 已經(jīng)獲取完更多
 
    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軸坐標(biāo)
 
    private boolean mIsDown;            // 是否按下
    private boolean mIsRefreshing;      // 是否下拉刷新中
    private boolean mIsFetchMoreing;    // 是否獲取更多中
    private boolean mIsPullUpDone;      // 是否回推完成
    private boolean mEnableAutoFetchMore;   // 是否允許自動獲取更多
 
    // 頭部文件的狀態(tài)
    private static final int HEADER_VIEW_STATE_IDLE = 0;            // 空閑
    private static final int HEADER_VIEW_STATE_NOT_OVER_HEIGHT = 1; // 沒有超過默認(rèn)高度
    private static final int HEADER_VIEW_STATE_OVER_HEIGHT = 2;     // 超過默認(rèn)高度
    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();
    }
 
    /**
     * 通知加載完了數(shù)據(jù),要放在Adapter.notifyDataSetChanged后面
     * 當(dāng)你加載完數(shù)據(jù)的時候,調(diào)用這個notifyDidLoad()
     * 才會隱藏頭部,并初始化數(shù)據(jù)等
     */
    public void notifyDidLoad() {
        mUIHandler.sendEmptyMessage(WHAT_DID_LOAD_DATA);
    }
 
    /**
     * 通知已經(jīng)刷新完了,要放在Adapter.notifyDataSetChanged后面
     * 當(dāng)你執(zhí)行完刷新任務(wù)之后,調(diào)用這個notifyDidRefresh()
     * 才會隱藏掉頭部文件等操作
     */
    public void notifyDidRefresh() {
        mUIHandler.sendEmptyMessage(WHAT_DID_REFRESH);
    }
 
    /**
     * 通知已經(jīng)獲取完更多了,要放在Adapter.notifyDataSetChanged后面
     * 當(dāng)你執(zhí)行完更多任務(wù)之后,調(diào)用這個notyfyDidMore()
     * 才會隱藏加載圈等操作
     */
    public void notifyDidMore() {
        mUIHandler.sendEmptyMessage(WHAT_DID_MORE);
    }
 
    /**
     * 設(shè)置監(jiān)聽器
     * @param listener
     */
    public void setOnPullDownListener(OnPullDownListener listener){
        mOnPullDownListener = listener;
    }
 
    /**
     * 獲取內(nèi)嵌的listview
     * @return ScrollOverListView
     */
    public ListView getListView(){
        return mListView;
    }
 
    /**
     * 是否開啟自動獲取更多
     * 自動獲取更多,將會隱藏footer,并在到達(dá)底部的時候自動刷新
     * @param index 倒數(shù)第幾個觸發(fā)
     */
    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
     * 具體實(shí)現(xiàn)下拉刷新等操作
     *
     * ==================================
     */
 
    /**
     * 初始化界面
     */
    private void initHeaderViewAndFooterViewAndListView(Context context){
        setOrientation(LinearLayout.VERTICAL);
        //setDrawingCacheEnabled(false);
        /*
         * 自定義頭部文件
         * 放在這里是因為考慮到很多界面都需要使用
         * 如果要修改,和它相關(guān)的設(shè)置都要更改
         */
        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);
 
        // 注意,圖片旋轉(zhuǎn)之后,再執(zhí)行旋轉(zhuǎn),坐標(biāo)會重新開始計算
        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 同樣是考慮到都是使用,所以放在這里
         * 同時因為,需要它的監(jiān)聽事件
         */
        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() {}
        };
    }
 
    /**
     * 在下拉和回推的時候檢查頭部文件的狀態(tài)</br>
     * 如果超過了默認(rèn)高度,就顯示松開可以刷新,
     * 否則顯示下拉可以刷新
     */
    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;
    }
 
    /*
     * ==================================
     * 實(shí)現(xiàn) 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;
        // 數(shù)量充滿屏幕才觸發(fā)
        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) {
        //當(dāng)頭部文件回推消失的時候,不允許滾動
        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;
        // 避免和點(diǎn)擊事件沖突
        if(mHeaderViewParams.height > 0){
            // 判斷頭文件拉動的距離與設(shè)定的高度,小了就隱藏,多了就固定高度
            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;
    }
 
}
復(fù)制代碼

第七步:這個java文件就是封裝數(shù)據(jù),然后調(diào)用上兩個文件就好了。廢話不多說,上代碼:::::

復(fù)制代碼
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.設(shè)置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();
                        }
                    }
                    // 訴它數(shù)據(jù)加載完畢;
                    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, "啊,你點(diǎn)中我了 " + position, Toast.LENGTH_SHORT).show();
    }
 
    // 模擬數(shù)據(jù)
    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"
    };
 
}
復(fù)制代碼

整個程序就這么完成了,總之,可以使用前兩個封裝好的文件,然后,調(diào)用就好了~~~~沒什么太難的地方。

 

源代碼下載地址:我是傳送門   我也是個傳送門

http:///android-listview-more-refresh.html

    本站是提供個人知識管理的網(wǎng)絡(luò)存儲空間,所有內(nèi)容均由用戶發(fā)布,不代表本站觀點(diǎn)。請注意甄別內(nèi)容中的聯(lián)系方式、誘導(dǎo)購買等信息,謹(jǐn)防詐騙。如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,請點(diǎn)擊一鍵舉報。
    轉(zhuǎn)藏 分享 獻(xiàn)花(0

    0條評論

    發(fā)表

    請遵守用戶 評論公約

    類似文章 更多

    色好吊视频这里只有精| 五月情婷婷综合激情综合狠狠| 国产户外勾引精品露出一区| 一级片二级片欧美日韩| 中文日韩精品视频在线| 亚洲欧美精品伊人久久| 精品精品国产欧美在线| 激情五月综五月综合网| 欧美精品久久99九九| 三级理论午夜福利在线看| 黄片免费观看一区二区| 暴力三级a特黄在线观看| 中文字幕不卡欧美在线| 美女被后入福利在线观看| 国内午夜精品视频在线观看| 好吊妞视频这里有精品| 国产麻豆一区二区三区在| 午夜国产精品福利在线观看| 午夜福利视频六七十路熟女| 夜夜躁狠狠躁日日躁视频黑人| 欧美色婷婷综合狠狠爱| 国产日韩欧美在线亚洲| 久草视频这里只是精品| 98精品永久免费视频| 99热九九热这里只有精品| 成人免费在线视频大香蕉| 国产性情片一区二区三区| 国产成人精品国产亚洲欧洲| 91福利免费一区二区三区| 精品亚洲一区二区三区w竹菊| 日本特黄特色大片免费观看| 免费特黄欧美亚洲黄片| 欧洲一区二区三区蜜桃| 日韩精品综合福利在线观看| 成人欧美精品一区二区三区| 国产又猛又大又长又粗| 又大又长又粗又猛国产精品| 老司机精品国产在线视频| 欧美亚洲三级视频在线观看| 国产高清精品福利私拍| 精品欧美在线观看国产|