Android教程網
  1. 首頁
  2. Android 技術
  3. Android 手機
  4. Android 系統教程
  5. Android 游戲
 Android教程網 >> Android技術 >> Android開發 >> 關於android開發 >> Android下拉刷新上拉加載更多的擴展ListView

Android下拉刷新上拉加載更多的擴展ListView

編輯:關於android開發

Android下拉刷新上拉加載更多的擴展ListView


下拉刷新上拉加載更多的擴展ListView

在很多APP我們都能看到,在一個列表上面,將手指往屏幕下面滑動,列表上方就會出現一個隱藏的View,一般寫有“下拉刷新”等字樣,意味著,我們將手指往下面滑動,字樣又會變成 “放開刷新” 字樣,這時候我們將手指放開屏幕,我們就會看到 字樣變為 “正在刷新..." 並且旁邊還有一個旋轉的進度在旋轉等待,過了1、2秒後,列表的新的數據加載完成,這個提示的view就又隱藏起來了。這就是Android中下拉刷新的控件,現在我們就自己來實現一個這樣的控件,首先我們來講解一下原理。如下圖:

1、listView通過addHeaderView(header)一個方法可以添加頭布局View即 header,這個header就是顯示下拉刷新的view,然後將header的topMargin設置為它高度header.getHeight()的負值,那麼它就被隱藏在了手機屏幕的頂部,如下圖中所示;

\

2、將listview設置滑動監聽setOnscrollListner,用來監聽用戶手指的滑動狀態,可以判斷用戶手指的按下,滑動,抬起等一整套完整的手指滑動事件,然後根據手指向下滑動的距離,動態的更新到listview的header的margin中,這樣整個listview就會往下滑動,此時隱藏在手機屏幕頂部的header也就會從屏幕頂部慢慢的滾動出來,如下圖所示。當header完全滾動出來後,這個時候listView向下滑動的距離Height大於了header的高度,這個時候就跟新header的顯示狀態,header就顯示為 "放開刷新",即放開手指listview就進行刷新操作。

\

3、當header顯示為釋放刷新的時候,這個時候手指離開屏幕,即點擊事件為MotionEvent.UP,這個時候屏幕就會顯示 ”正在刷新...“ 並且左邊會有刷新的進度條在進行刷新等待,等到主Acitivity的新數據加載完成後就會隱藏掉header,這樣一個完正的下拉刷新原理就講完了。

\

\

 

 

我們講完了下拉刷新,截下拉我們講講上拉加載更多。

在很多listview列表數據中,當我們拉到底部時,就會出現一個 圓形進度條和一個”正在加載更多...“,主要是用於分頁加載網路數據,在我們訪問網絡數據時,如果數據較多,基本都會使用分頁處理數據,讓數據一批一批的加載進來,這樣就會緩解手機端訪問大量數據的壓力,畢竟數據多,加載時間就會長,用戶的等待時間也會增加,不利於用戶體驗。所以上拉加載更多,就在listview中使用了起來,也是android開發必備的知識。

 

如下圖所示,listview通過addFooterView(View view)就可以通過判斷是不是滑動到了底部,然後給listview添加底部view。讓後讓activity實現listview的刷新接口,當listview滑動到了底部,然後響應接口,當加載更多的實現完成之後,就開始設置listiview的loadingComplete()方法,就將加載更多的view給隱藏掉。

 

\\

好了原理就是那樣,現在我們看看效果

 

\

\

 

下面是 RefreshListView的代碼

 

package com.example.myfirst.pulltorefreshlist;

import android.content.Context;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.view.View;
import android.view.animation.Animation;
import android.view.animation.RotateAnimation;
import android.widget.AbsListView;
import android.widget.AbsListView.OnScrollListener;
import android.widget.ImageView;
import android.widget.ListView;
import android.widget.ProgressBar;
import android.widget.TextView;

import java.text.SimpleDateFormat;

public class RefreshListView extends ListView implements OnScrollListener {

    /**
     * 下拉刷新部分
     */
    private static final String TAG = "RefreshListView";
    private int firstVisibleItemPosition;//listview中第一個可見item所在的位置position
    private int downY;//手指在Y軸下拉滑動的距離
    private int headerViewHeight;//下拉刷新view的高度
    private View headerView; //下拉刷新的view
    private final int DOWN_PULL_REFERESH = 0;//“下拉刷新”狀態
    private final int RELEASE_REFRESH = 1;//“放開刷新”狀態
    private final int REFRESHING = 2;//“正在刷新”狀態
    private int currentState = DOWN_PULL_REFERESH;//listView當前的狀態,默認為”下拉刷新“狀態
    private Animation upAnimation; //下拉箭頭變為向上箭頭的動畫
    private Animation downAnimation; //上拉箭頭變為向下箭頭的動畫
    private ImageView ivArrow; //下拉箭頭
    private ProgressBar mProgressBar; //進度條
    private TextView tvState; //顯示狀態的文本
    private TextView tvLastUpdateTimes; //顯示最後更新的時間

    /**
     * 底部加載更多部分
     */
    private boolean isScrollToBottom;//判斷是不是滑到了底部
    private View footerView; //底部的footer   view
    private int footerViewHeight; //底部view的高度
    private boolean isLoadingMore = false; //判斷是不是"加載更多"

    /**
     * listview的接口,監聽listview的下來刷新和上拉加載更多
     */
    private OnRefreshListener mOnRefreshListener;

    public RefreshListView(Context context, AttributeSet attrs) {
        super(context, attrs);
        initHeaderView();
        initFooterView();
        this.setOnScrollListener(this);
    }

    /**
     * 初始化底部view
     */
    private void initFooterView() {
        footerView = View.inflate(getContext(), R.layout.footer_layout, null);
        //設置(0,0)以便系統測量footerView的寬高
        footerView.measure(0, 0);
        footerViewHeight = footerView.getMeasuredHeight();
        footerView.setPadding(0, -footerViewHeight, 0, 0);
        this.addFooterView(footerView);
    }

    /**
     * 初始化頂部view
     */
    private void initHeaderView() {
        headerView = View.inflate(getContext(), R.layout.header_layout, null);
        ivArrow = (ImageView) headerView.findViewById(R.id.pull_to_refresh_icon);
        mProgressBar = (ProgressBar) headerView.findViewById(R.id.refresh_progressbar);
        tvState = (TextView) headerView.findViewById(R.id.hint_text);
        tvLastUpdateTimes = (TextView) headerView.findViewById(R.id.refresh_time);

        //最近更新
        tvLastUpdateTimes.setText("最近更新:" + getLastUpdateTime());
        //設置(0,0)以便系統測量footerView的寬高
        headerView.measure(0, 0);
        headerViewHeight = headerView.getMeasuredHeight();
        headerView.setPadding(0, -headerViewHeight, 0, 0);
        this.addHeaderView(headerView);
        initAnimation();
    }

    /**
     * 獲取最近更新時間
     */
    private String getLastUpdateTime() {
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-mm-dd HH:mm:ss");
        return sdf.format(System.currentTimeMillis());
    }

    /**
     * 初始化動畫
     */
    private void initAnimation() {
        upAnimation = new RotateAnimation(0f, -180f, Animation.RELATIVE_TO_SELF, 0.5f, Animation.RELATIVE_TO_SELF, 0.5f);
        upAnimation.setDuration(500);
        upAnimation.setFillAfter(true);//設為true,表示動畫完成後,保持動畫後的狀態

        downAnimation = new RotateAnimation(-180f, -360f, Animation.RELATIVE_TO_SELF, 0.5f, Animation.RELATIVE_TO_SELF, 0.5f);
        downAnimation.setDuration(500);
        downAnimation.setFillAfter(true);//設為true,表示動畫完成後,保持動畫後的狀態

    }

    /**
     * listView的touche事件,通過判斷手指在listview上面的,按下、滑動、抬起等一套手指動作,來實現
     * 下拉刷新和上拉加載更多
     *
     * @param ev
     * @return
     */
    @Override
    public boolean onTouchEvent(MotionEvent ev) {
        switch (ev.getAction()) {
            case MotionEvent.ACTION_DOWN:
                downY = (int) ev.getY();
                break;
            case MotionEvent.ACTION_MOVE:
                int moveY = (int) ev.getY();
                //獲取滑動距離一半長度,以便手指在屏幕上面滑動了很長一段距離,headerview也不是很高,
                //主要為了美觀,你可以不用除2,看你自己的設計,不過除2顯示效果要好點
                int diff = (moveY - downY) / 2;
                //設置頂部view距離頂部的padding距離
                int paddingTop = -headerViewHeight + diff;

                //如果當前可見的第一個position為0,
                if (firstVisibleItemPosition == 0 && -headerViewHeight < paddingTop) {
                    //paddingTop>0說明headerView完全拉出了頂部,並且當前狀態為”下拉刷新“
                    //則把當前狀態改為”放開刷新“,並且調用refeshHeaderView()更新界面
                    if (paddingTop > 10 && currentState == DOWN_PULL_REFERESH) {
                        currentState = RELEASE_REFRESH;
                        refreshHeaderView();
                    } //paddingTop<0說明headerView沒有完全拉出了頂部,並且當前狀態為”放開刷新“
                    //則把當前狀態改為”下拉刷新“,並且調用refeshHeaderView()更新界面;
                    //這種情況就是,當完全拉出來之後,手指沒有抬起,然後往又回到頂部
                    else if (paddingTop < 10 && currentState == RELEASE_REFRESH) {
                        currentState = DOWN_PULL_REFERESH;
                        refreshHeaderView();
                    }
                    //動態刷新headerView的頂部padding,這樣lisview就在動態的變化
                    headerView.setPadding(0, paddingTop, 0, 0);
                    return true;
                }
                break;
            //手指抬起時,判斷listview當前的狀態
            case MotionEvent.ACTION_UP:
                //判斷當前的狀態
                if (currentState == RELEASE_REFRESH) {
                    //如果是”放開刷新“,讓headerView的padding都為0
                    headerView.setPadding(0, 0, 0, 0);
                    // 把當前的狀態設為”正在刷新“
                    currentState = REFRESHING;
                    refreshHeaderView();

                    //判斷外面外面有沒有設置刷新的接口
                    if (mOnRefreshListener != null) {
                        //如果設置了接口,就調用接口中的下拉刷新的方法
                        mOnRefreshListener.onDownPullRefresh();
                    }
                } else if (currentState == DOWN_PULL_REFERESH) {
                    //如果當前狀態是”下拉刷新“狀態,則將headerView隱藏掉
                    headerView.setPadding(0, -headerViewHeight, 0, 0);
                }
                break;
            default:
                break;
        }

        return super.onTouchEvent(ev);
    }

    /**
     * 根據當前狀態currentState來更新下拉刷新view界面的控件顯示內容?
     */
    private void refreshHeaderView() {
        switch (currentState) {
            case DOWN_PULL_REFERESH:
                tvState.setText("下拉刷新");
                ivArrow.startAnimation(downAnimation);
                break;
            case RELEASE_REFRESH:
                tvState.setText("放開刷新");
                ivArrow.startAnimation(upAnimation);
                break;
            case REFRESHING:
                ivArrow.clearAnimation();
                ivArrow.setVisibility(View.GONE);
                mProgressBar.setVisibility(View.VISIBLE);
                tvState.setText("正在刷新...");
                break;
            default:
                break;
        }

    }

    /**
     * 監聽listview滾動的狀態變化,如果滑到了底部,就“加載更多..."
     */
    @Override
    public void onScrollStateChanged(AbsListView view, int scrollState) {

        if (scrollState == SCROLL_STATE_IDLE || scrollState == SCROLL_STATE_FLING) {
            if (isScrollToBottom && !isLoadingMore) {
                isLoadingMore = true;
                footerView.setPadding(0, 0, 0, 0);
                this.setSelection(this.getCount());

                if (mOnRefreshListener != null) {
                    mOnRefreshListener.onLoadingMore();
                }
            }
        }
    }

    /**
     * 監聽listview滾動的狀態變化,判斷當前是不是滑到了底部
     *
     * @param view
     * @param firstVisibleItem
     * @param visibleItemCount
     * @param totalItemCount
     */
    @Override
    public void onScroll(AbsListView view, int firstVisibleItem, int visibleItemCount, int totalItemCount) {
        firstVisibleItemPosition = firstVisibleItem;
        if (getLastVisiblePosition() == (totalItemCount - 1)) {
            isScrollToBottom = true;
        } else {
            isScrollToBottom = false;
        }

    }

    /**
     * 設置監聽接口,當為
     *
     * @param listener
     */
    public void setOnRefreshListener(OnRefreshListener listener) {
        mOnRefreshListener = listener;
    }

    /**
     * 為外界提供的方法,當Activity中的數據加載完後,就調用這個方法來隱藏頂部的headerView
     */
    public void onRefreshComplete() {
        headerView.setPadding(0, -headerViewHeight, 0, 0);
        ivArrow.setVisibility(View.VISIBLE);
        mProgressBar.setVisibility(View.GONE);
        tvState.setText("下拉刷新");
        tvLastUpdateTimes.setText("最近更新時間:" + getLastUpdateTime());
        currentState = DOWN_PULL_REFERESH;
    }

    /**
     * 為外界提供的方法,當Activity中的加載更多數據加載完後,就調用這個方法來隱藏底部的footerView
     */
    public void loadMoreComplete() {
        headerView.setPadding(0, -headerViewHeight, 0, 0);
        isLoadingMore = false;
    }

    /**
     * 設置接口,供外界實現,監聽listview的刷新和加載更多的狀態
     */
    public interface OnRefreshListener {
        /**
         * 下拉刷新
         */
        void onDownPullRefresh();

        /**
         * 上拉加載更多
         */
        void onLoadingMore();
    }
}

 

  1. 上一頁:
  2. 下一頁:
熱門文章
閱讀排行版
Copyright © Android教程網 All Rights Reserved