1. 程式人生 > >Android ListView 下拉重新整理,上拉載入更多,帶動畫 自定義控制元件

Android ListView 下拉重新整理,上拉載入更多,帶動畫 自定義控制元件

之前每次 專案中用到ListView 的 下拉重新整理 以及上拉分頁載入 都是 用的 網上 下載 的 類庫,

使用起來 諸多不便 ,於是 趁著有空 ,自己封裝了ListView 讓其 實現 下拉重新整理,以及分頁載入功能。

以下是 效果圖:

當 滑動到 ListView 頂部 或 尾部 時,再次手指上拉或下拉 則會 觸發 ListView 的 重新整理 ,並 顯示 重新整理 動畫,完成後動畫會 緩慢消失。


Demo 下載 地址:點選開啟連結

具體 實現原理:

首先對 ListView 要設定 OnScrollListener 監聽 其 滑動 狀態 ,並 記錄此 狀態。

ListView的 滑動 狀態 有 三種

靜止狀態,SCROLL_STATE_IDLE
手指滾動狀態,SCROLL_STATE_TOUCH_SCROLL
手指不動了,但是螢幕還在滾動狀態。SCROLL_STATE_FLING

上下拉重新整理 時 ListView的 滾動狀態 必須為 手指滾動才觸發重新整理。

還要 對 ListView 設定 觸控 監聽。

判斷 ListView 的 滑動 方向,計算其 手指拖動距離,以及手指擡起時的 重新整理動畫的 狀態

以下是 ListView 的 觸控 和 滾動 監聽 程式碼

首先 在 滾動 監聽 了 記錄 當前 的 滾動狀態。

然後 在 觸控監聽裡  當狀態 為 Action.Move 移動 時,判斷滾動的 方向,以及 ListView 當前位置 處於頂部還是底部,並且 是否正在重新整理。

然後 根據 手指 移動的 距離 除以相應倍數 ,讓 重新整理動畫 控制元件 緩慢 出現。 在Action.Up 中 判斷 當前的 重新整理控制元件 顯示 的 高度 是否 觸發 重新整理 方法。


    int currentScorllState;

    @Override
    public void onScrollStateChanged(AbsListView view, int scrollState) {
        currentScorllState = scrollState;
    }

    @Override
    public void onScroll(AbsListView view, int firstVisibleItem,
                         int visibleItemCount, int totalItemCount) {
    }

    boolean rememberFreshYTag = true;
    float freshY;
    float tempY;
    int times = 3;
    boolean downTag = false;
    float y;

    @Override
    public boolean onTouch(View view, MotionEvent motionEvent) {
        y = motionEvent.getY();
        switch (motionEvent.getAction()) {
            case MotionEvent.ACTION_MOVE:
                float scrollHeight = y - tempY;
                if (scrollHeight > 0) {
                    downTag = true;
                } else {
                    downTag = false;
                }
                if (currentScorllState == OnScrollListener.SCROLL_STATE_TOUCH_SCROLL
                        && this.getFirstVisiblePosition() == 0
                        && this.getTop() == 0
                        && downTag
                        && !freshingTag
                        ) {
                    topFreshTag = true;
                    if (rememberFreshYTag) {
                        freshY = y;
                    }
                    rememberFreshYTag = false;

                    float min = Math.min(headHeight + headHeight / 2, (y - freshY) / times);
                    imageViewHead.setPadding(0, (int) (-headHeight + min), 0, 0);
                    Log.i("testss", "topFresh" + y);
                } else if (currentScorllState == OnScrollListener.SCROLL_STATE_TOUCH_SCROLL
                        && this.getLastVisiblePosition() == getCount() - 1
                        && this.getBottom() == this.getHeight()
                        && !downTag
                        && !freshingTag
                        ) {
                    bottomFreshTag = true;
                    if (rememberFreshYTag) {
                        freshY = y;
                    }
                    rememberFreshYTag = false;
                    float min = Math.min(footHeight + footHeight / 2, -(y - freshY));
                    imageViewFoot.setPadding(0, 0, 0, (int) (-footHeight + min));

                    Log.i("testss", "buttomFresh" + y + "---" + freshY);
                }
                break;
            case MotionEvent.ACTION_UP:
                if (topFreshTag && !freshingTag) {
                    Log.i("testss", "uptopFreshTag");
                    // 手指 擡起時 符合 條件 則 觸發 頂部重新整理
                    judgeToFresh(TOP_FRESH, imageViewHead, headHeight);
                }
                if (bottomFreshTag && !freshingTag) {
//                    Log.i("testss", "upbottomFreshTag");
                    // 手指 擡起時 符合 條件 則 觸發 底部重新整理
                    judgeToFresh(BOTTOM_FRESH, imageViewFoot, footHeight);
                }
                break;
        }
        tempY = y;
        return super.onTouchEvent(motionEvent);
    }


以下 是判斷 是否 重新整理的方法

 /**
     * 判斷 是否 觸發 重新整理
     *
     * @param freshType 重新整理 的型別 頂部重新整理 或 底部重新整理
     * @param imageView 重新整理動畫 的 控制元件
     * @param height    當前 重新整理動畫 控制元件 顯示 的 高度
     */
    private void judgeToFresh(int freshType, ImageView imageView, int height) {

        int paddingHeight = freshType == TOP_FRESH ? imageView.getPaddingTop() : imageView.getPaddingBottom();
        if (paddingHeight == height / 2) {
            imageView.setPadding(0, 0, 0, 0);
            freshingTag = true;
            if (freshType == TOP_FRESH) {
                onTopFresh();
            } else {
                onBottomFresh();
            }
        } else {
            dissHeadOrFootView(imageView, freshType, -paddingHeight, height);
        }
    }

    /**
     * 開始 頂部 重新整理
     */
    private void onTopFresh() {
        // 開啟 動畫
        startOrStopAnimation(imageViewHead, true);
        /**
         * 如果 設定 了外部 監聽
         * 則 呼叫 外部監聽 的 重新整理 方法
         * 否則 過1s後 自動完成 重新整理動畫
         */
        if (onListViewFreshListener == null) {
            tempHandler.sendEmptyMessageDelayed(TOP_FRESH, 1000);
        } else {
            onListViewFreshListener.onTopFreshing();
        }
    }

    /**
     * 開始 底部 重新整理
     */
    private void onBottomFresh() {
        // 開啟 動畫
        startOrStopAnimation(imageViewFoot, true);
        /**
         * 如果 設定 了外部 監聽
         * 則 呼叫 外部監聽 的 重新整理 方法
         * 否則 過1s後 自動完成 重新整理動畫
         */
        if (onListViewFreshListener == null) {
            tempHandler.sendEmptyMessageDelayed(BOTTOM_FRESH, 1000);
        } else {
            onListViewFreshListener.onBottomFreshing();
        }
    }


Demo 下載 地址:點選開啟連結