自定義ListView下拉刷新,上拉加載

/**
 * Created by on 2016/12/2.
 * 自定義listview:
 *      一、下拉刷新:
 *          1. 添加頭部佈局,並設置位置隱藏
 *          2. 監聽滑動事件,判斷當前顯示在最頂端的item是否是第一個item
 *          3. 監聽onTouch事件,根據下拉的距離來判斷下來狀態的變化
 *      二、加載更多:
 *          1. 添加底部佈局,並隱藏
 *          2. 監聽滑動事件,判斷最後顯示的item是不是最後一個item來決定是否加載更多
 *      這裏通過傳遞參數的方式來傳遞handler來延遲刷新
 *      (推薦)通過接口回調的方式可以實現加載數據
 */
public class ReFlashListView extends ListView implements AbsListView.OnScrollListener{

    private Handler handler;//這個handler用來做一個延時處理刷新

    private View header;//頭佈局
    private int headerHeight;//header的高度
    int firstVisibleItem;//listview中可見的第一個item的位置
    int visibleItemCount;//可見的item的數量
    int totalItemCounts;//已經顯示出來的總數量
    int scrollState;//滑動狀態

    int state;//滑動的狀態
    final int NONE = 0; //正常狀態
    final int PULL = 1; //提示下拉狀態
    final int RELSE = 2; //提示釋放狀態
    final int RELSING = 3; //正在刷新狀態

    private boolean isTop = false; //判斷按下的時候當前顯示在最上面一個item是listview的第一個item
    private int stateY;//按下的時候Y軸的位置

    private ImageView iv_header;
    private TextView tv_header;
    private ProgressBar pg_header;

    private View footer;//底部佈局
    private boolean isLoading = false;


    public ReFlashListView(Context context) {
        super(context);
        initView(context);
    }

    public ReFlashListView(Context context, AttributeSet attrs) {
        super(context, attrs);
        initView(context);
    }

    public ReFlashListView(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        initView(context);
    }

    /**
     * 實例化handler
     */
    public void setListViewHandler(Handler handler){
        this.handler = handler;
    }

    /**
     * 給ListView添加頭佈局
     * @param context
     */
    private void initView(Context context){
        header = LayoutInflater.from(context).inflate(R.layout.activity_view_listview_header, null);
        iv_header = (ImageView) header.findViewById(R.id.iv_header);
        tv_header = (TextView) header.findViewById(R.id.tv_header);
        pg_header = (ProgressBar) header.findViewById(R.id.pg_header);
        measureHeight(header);
        headerHeight = header.getMeasuredHeight();
        initHeaderTopPadding();
        this.addHeaderView(header);
        loadFooter(context);
        this.setOnScrollListener(this);
    }

    /**
     * 加載底部佈局
     */
    private void loadFooter(Context context){
        footer = LayoutInflater.from(context).inflate(R.layout.activity_view_listview_footer, null);
        footer.findViewById(R.id.ll_load_more).setVisibility(View.GONE);
        this.addFooterView(footer);
    }

    /**
     * 初始化header的位置
     */
    public void initHeaderTopPadding(){
        setTopPadding(-headerHeight);
    }

    /**
     * 設置header的高度:隱藏header
     */
    private void setTopPadding(int topPadding) {
        header.setPadding(header.getPaddingLeft(), topPadding, header.getPaddingRight(), header.getPaddingBottom());
    }

    /**
     * 高度父佈局當前view的寬高
     *      如果沒有這一步,header.getMeasuredHeight() == 0
     */
    private void measureHeight(View view){
        ViewGroup.LayoutParams p = view.getLayoutParams();
        if(p == null){
            p = new ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT , ViewGroup.LayoutParams.WRAP_CONTENT);
        }
        int width = ViewGroup.getChildMeasureSpec(0, 0, p.width);
        int height;
        int temHeight = p.height;
        if(temHeight > 0){
            height = MeasureSpec.makeMeasureSpec(temHeight , MeasureSpec.EXACTLY);
        }else {
            height = MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED);
        }
        view.measure(width, height);
    }

    /**
     * @param view
     * @param scrollState:即滑動的狀態。分爲三種 0,1,2
                            0 表示停止滑動的狀態 SCROLL_STATE_IDLE
                            1表示正在滾動,用戶手指在屏幕上 SCROLL_STATE_TOUCH_SCROLL
                            2表示正在滑動。用戶手指已經離開屏幕 SCROLL_STATE_FLING
     */
    @Override
    public void onScrollStateChanged(AbsListView view, int scrollState) {
        this.scrollState = scrollState;
        if((firstVisibleItem + visibleItemCount) == totalItemCounts && scrollState == SCROLL_STATE_IDLE){
            if(!isLoading){
                //顯示出footer,並在這裏加載數據
                footer.findViewById(R.id.ll_load_more).setVisibility(View.VISIBLE);
                /**
                 * TODO:加載數據
                 */
            }
        }
    }

    /**
     * @param view
     * @param firstVisibleItem : 第一個可見的item的位置
     * @param visibleItemCount : 可見的item的數量
     * @param totalItemCount : 總的數量
     */
    @Override
    public void onScroll(AbsListView view, int firstVisibleItem, int visibleItemCount, int totalItemCount) {
        this.firstVisibleItem = firstVisibleItem;
        this.visibleItemCount = visibleItemCount;
        this.totalItemCounts = totalItemCount;
    }

    /**
     * 監聽滑動狀態的改變
     * @param ev
     * @return
     */
    @Override
    public boolean onTouchEvent(MotionEvent ev) {
        switch (ev.getAction()){
            case MotionEvent.ACTION_DOWN:
                if(firstVisibleItem == 0){//當前顯示在最上面一個item是listview的第一個item
                    state = NONE;//設置狀態,表示繼續下拉可以觸發刷新
                    isTop = true;
                    stateY = (int) ev.getY();
                }
                break;
            case MotionEvent.ACTION_MOVE:
                reFlashing(ev);
                break;
            case MotionEvent.ACTION_UP:
                if(state == RELSE){
                    state = RELSING;
                    reFlasTip();
                    //加載數據               
                    /**
                     * TODO:刷新數據
                     */
}else if(state == PULL){ state = NONE; isTop = false; reFlasTip(); } break; } return super.onTouchEvent(ev); } /** * 判斷移動過程中的操作 */ private void reFlashing(MotionEvent ev){ if(!isTop){ return; } int evY = (int) ev.getY(); int spaceY = evY - stateY; int topPadding = spaceY - headerHeight; if(topPadding >= headerHeight * 3){ topPadding = headerHeight * 2; } switch (state){ case NONE: if(spaceY >= 0){ //表示往下拉動 state = PULL; reFlasTip(); } break; case PULL: setTopPadding(topPadding); if(spaceY >= headerHeight+20 && scrollState == SCROLL_STATE_TOUCH_SCROLL){ //表示往下拉動,並且正在滾動 state = RELSE; reFlasTip(); }else if(spaceY <= 0){ state = NONE; isTop = false; reFlasTip(); } break; case RELSE: setTopPadding(topPadding); if(spaceY < headerHeight){ state = PULL; reFlasTip(); }else if(spaceY <= 0){ state = NONE; isTop = false; reFlasTip(); } break; } } /** * 根據下拉狀態的變化改變header的提示 */ private void reFlasTip(){ switch (state){ case NONE: setTopPadding(-headerHeight); break; case PULL: tv_header.setText("下拉可以刷新"); break; case RELSE: tv_header.setText("鬆開可以刷新"); break; case RELSING: setTopPadding(headerHeight); tv_header.setText("正在刷新"); break; } }}
發佈了34 篇原創文章 · 獲贊 0 · 訪問量 9329
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章