1. 程式人生 > >Android開發之下拉重新整理和上拉載入框架PullToRefresh的詳談

Android開發之下拉重新整理和上拉載入框架PullToRefresh的詳談

最近在負責了兩三個專案,然後很多地方展示列表資料都用到了下拉重新整理或者上拉載入或者兩者兼有。

  • 我用的是一個開源框架:Ultra Pull to Refresh with Load More
  • 這是一個GitHub上的開源專案,本分支是對原有的Ultra Pull To Refresh進行了修改,使得其支援了上拉載入更多。

下面來說一下在專案中的使用吧!

  • 首先你需要先在你的開發工具中引用這個第三方庫,在你的gradle中新增:

compile ‘in.srain.cube:ptr-load-more:1.0.6’

然後等待studio同步一下配置即可以在xml檔案中使用該控制元件了。

  • 該框架你需要在xml中引用控制元件如下:
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height
="match_parent" tools:context="com.example.demo.ultrapulltorefreshdemo.MainActivity">
<in.srain.cube.views.ptr.PtrFrameLayout android:id="@+id/ptr_frame" android:layout_width="match_parent" android:layout_height="match_parent" > <!-- 這裡可以是任何view,是不是很棒 -->
<ImageView android:id="@+id/iv_demo" android:src="@mipmap/demo" android:layout_width="match_parent" android:layout_height="match_parent" /> </in.srain.cube.views.ptr.PtrFrameLayout> </RelativeLayout>

上面的 in.srain.cube.views.ptr.PtrFrameLayout 就是需要在xml佈局檔案中使用的view,這是一定要新增的,所有的操作都是根據這個view來實現的。

然後裡面可以新增任何控制元件,你想操作textview、imageview、listview或者其他任何view,你只要新增到這個view裡面即可。我這裡用的是一個imageview。

然後你需要給這個view加一些必要的屬性,用來控制下拉時的阻尼係數,控制重新整理回彈時間等等。

  • 這些屬性的設定有兩種配置方法

一種是在xml中配置,示例如下:

<in.srain.cube.views.ptr.PtrFrameLayout
    android:id="@+id/store_house_ptr_frame"
    xmlns:cube_ptr="http://schemas.android.com/apk/res-auto"
    android:layout_width="match_parent"
    android:layout_height="match_parent"

    cube_ptr:ptr_resistance="1.7"
    cube_ptr:ptr_ratio_of_header_height_to_refresh="1.2"
    cube_ptr:ptr_duration_to_close="300"
    cube_ptr:ptr_duration_to_close_header="2000"
    cube_ptr:ptr_keep_header_when_refresh="true"
    cube_ptr:ptr_pull_to_fresh="false" >

    <LinearLayout
        android:id="@+id/store_house_ptr_image_content"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:background="@color/cube_mints_333333"
        android:clickable="true"
        android:padding="10dp">

        <in.srain.cube.image.CubeImageView
            android:id="@+id/store_house_ptr_image"
            android:layout_width="match_parent"
            android:layout_height="match_parent" />
    </LinearLayout>

</in.srain.cube.views.ptr.PtrFrameLayout>

第二種是在程式碼中配置,示例如下:

// 頭部阻尼係數
        ptr_frame.setResistanceHeader(1.7f);
        // 底部阻尼係數
        ptr_frame.setResistanceFooter(1.7f);
        // 預設1.2f,移動達到頭部高度1.2倍時觸發重新整理操作
        ptr_frame.setRatioOfHeaderHeightToRefresh(1.2f);
        // 頭部回彈時間
        ptr_frame.setDurationToCloseHeader(1000);
        // 底部回彈時間
        ptr_frame.setDurationToCloseFooter(1000);
        // 釋放重新整理
        ptr_frame.setPullToRefresh(false);
        // 釋放時恢復到重新整理狀態的時間
        ptr_frame.setDurationToBackHeader(200);
        ptr_frame.setDurationToBackFooter(200);

其中ptr_frame是PtrFrameLayout控制元件(即xml中使用的view)。

上面兩種配置方法中用到了下面這些配置:

  • 阻尼係數

預設: 1.7f,越大,感覺下拉時越吃力。

  • 觸發重新整理時移動的位置比例

預設,1.2f,移動達到頭部高度1.2倍時可觸發重新整理操作。

  • 回彈延時

預設 200ms,回彈到重新整理高度所用時間

  • 頭部回彈時間

預設1000ms

  • 重新整理時保持頭部

預設值 true.

  • 下拉重新整理 / 釋放重新整理

預設為釋放重新整理

  • 屬性配置完成後再進行下一步 新增頭部重新整理佈局,如下所示:
// Matrial風格頭部的實現
        final MaterialHeader header = new MaterialHeader(this);
        header.setPadding(0, PtrLocalDisplay.dp2px(15),0,0);
        ptr_frame.setHeaderView(header);
        ptr_frame.addPtrUIHandler(header);

當然有其他的風格的頭佈局,你們自己找自己喜歡的新增即可。

  • 頭佈局新增完後再新增尾佈局實現載入更多,如下:
// 經典的底部佈局實現
        PtrClassicDefaultFooter footer = new PtrClassicDefaultFooter(this);
        footer.setPadding(0, PtrLocalDisplay.dp2px(15),0,0);
        ptr_frame.setFooterView(footer);
        ptr_frame.addPtrUIHandler(footer);

這裡底部佈局暫時就一種,是預設的。

當頭佈局和尾佈局都新增後,再新增最後一個方法就可以實現下拉重新整理和上拉載入了,這裡也有兩種方法可以實現

一種是用PtrDefaultHandler2:實現了預設的 checkCanDoLoadMore() 邏輯,可以適用於大部分的View。如下:

/**
         * 不用判斷什麼時候重新整理和載入,方法裡有自己的判斷,適合大多數的情況。你只需要關心重新整理和載入需要執行什麼操作
         */
        ptr_frame.setPtrHandler(new PtrDefaultHandler2() {
            // 載入更多開始會執行該方法
            @Override
            public void onLoadMoreBegin(PtrFrameLayout frame) {
                // 這裡做一些載入的操作
                // LoadMore();

                // 用於關閉上拉載入
                ptr_frame.refreshComplete();
            }

            // 重新整理開始會執行該方法
            @Override
            public void onRefreshBegin(PtrFrameLayout frame) {
                // 這裡做一些重新整理操作
                // Refresh();

                // 用於關閉下拉重新整理
                ptr_frame.refreshComplete();
            }
        });

還有一種是PtrHandler2,該方法你可以自己判斷重新整理和載入的邏輯,擴充套件性的體現,特殊情況會用到該方法的實現:

/**
         *  下拉重新整理和上拉載入更多的實現
         *  這裡你可以自己判斷什麼時候重新整理和載入 特殊情況也不用怕有問題
         */
        ptr_frame.setPtrHandler(new PtrHandler2() {
            // 判斷是否可以上拉載入 這裡使用者可以自己控制什麼時候做載入操作
            // 返回true表示可以載入,返回false表示不可以載入
            @Override
            public boolean checkCanDoLoadMore(PtrFrameLayout frame, View content, View footer) {
                return true;
            }

            // 載入更多開始會執行該方法
            @Override
            public void onLoadMoreBegin(PtrFrameLayout frame) {
                // 這裡做一些載入的操作
                // LoadMore();

                // 用於關閉上拉載入
                ptr_frame.refreshComplete();
            }

            // 判斷是否可以下拉重新整理 這裡使用者可以自己控制什麼時候做重新整理操作
            // 返回true表示可以重新整理,返回false表示不可以重新整理
            @Override
            public boolean checkCanDoRefresh(PtrFrameLayout frame, View content, View header) {
                return true;
            }

            // 重新整理開始會執行該方法
            @Override
            public void onRefreshBegin(PtrFrameLayout frame) {
                // 這裡做一些重新整理操作
                // Refresh();

                // 用於關閉下拉重新整理
                ptr_frame.refreshComplete();
            }
        });
  • 還有一個很好的方法,你可以任意的開啟/關閉header或者footer如下:

setMode(Mode): 通過呼叫setMode, 你可以任意的開啟/關閉header或者footer。引數型別是一個列舉變數,可以通過以下方式呼叫:setMode(Mode.BOTH).

上面這些步驟做完,就基本實現了重新整理和載入功能。

  • 最後給出demo的實現程式碼,這裡大家可以做參考:
package com.example.demo.ultrapulltorefreshdemo;

import android.app.Activity;
import android.os.Bundle;
import android.view.View;

import in.srain.cube.views.ptr.PtrClassicDefaultFooter;
import in.srain.cube.views.ptr.PtrDefaultHandler2;
import in.srain.cube.views.ptr.PtrFrameLayout;
import in.srain.cube.views.ptr.PtrHandler2;
import in.srain.cube.views.ptr.header.MaterialHeader;
import in.srain.cube.views.ptr.util.PtrLocalDisplay;

public class MainActivity extends Activity {

    private PtrFrameLayout ptr_frame;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        // 獲取PtrFrameLayout控制元件
        ptr_frame = (PtrFrameLayout) findViewById(R.id.ptr_frame);
        // PtrFrameLayout屬性設定及重新整理載入的實現
        setPtrFrameAttribute();

    }

    /***
     * 必要屬性設定及重新整理載入的實現
     */
    private void setPtrFrameAttribute() {
        // 頭部阻尼係數
        ptr_frame.setResistanceHeader(1.7f);
        // 底部阻尼係數
        ptr_frame.setResistanceFooter(1.7f);
        // 預設1.2f,移動達到頭部高度1.2倍時觸發重新整理操作
        ptr_frame.setRatioOfHeaderHeightToRefresh(1.2f);
        // 頭部回彈時間
        ptr_frame.setDurationToCloseHeader(1000);
        // 底部回彈時間
        ptr_frame.setDurationToCloseFooter(1000);
        // 釋放重新整理
        ptr_frame.setPullToRefresh(false);
        // 釋放時恢復到重新整理狀態的時間
        ptr_frame.setDurationToBackHeader(200);
        ptr_frame.setDurationToBackFooter(200);

        // Matrial風格頭部的實現
        final MaterialHeader header = new MaterialHeader(this);
        header.setPadding(0, PtrLocalDisplay.dp2px(15),0,0);
        ptr_frame.setHeaderView(header);
        ptr_frame.addPtrUIHandler(header);

        // 經典的底部佈局實現
        PtrClassicDefaultFooter footer = new PtrClassicDefaultFooter(this);
        footer.setPadding(0, PtrLocalDisplay.dp2px(15),0,0);
        ptr_frame.setFooterView(footer);
        ptr_frame.addPtrUIHandler(footer);

        // 設定支援重新整理和載入更多 可以任意開啟或者關閉某一個特性(開關)
        ptr_frame.setMode(PtrFrameLayout.Mode.BOTH);

        // 進入介面自動重新整理
        ptr_frame.post(new Runnable() {
            @Override
            public void run() {
                // 進入介面自動重新整理
                 ptr_frame.autoRefresh();
            }
        });

        /**
         *  下拉重新整理和上拉載入更多的實現
         *  這裡你可以自己判斷什麼時候重新整理和載入 特殊情況也不用怕有問題
         */
        /**
        ptr_frame.setPtrHandler(new PtrHandler2() {
            // 判斷是否可以上拉載入 這裡使用者可以自己控制什麼時候做載入操作
            // 返回true表示可以載入,返回false表示不可以載入
            @Override
            public boolean checkCanDoLoadMore(PtrFrameLayout frame, View content, View footer) {
                return true;
            }

            // 載入更多開始會執行該方法
            @Override
            public void onLoadMoreBegin(PtrFrameLayout frame) {
                // 這裡做一些載入的操作
                // LoadMore();

                // 用於關閉上拉載入
                ptr_frame.refreshComplete();
            }

            // 判斷是否可以下拉重新整理 這裡使用者可以自己控制什麼時候做重新整理操作
            // 返回true表示可以重新整理,返回false表示不可以重新整理
            @Override
            public boolean checkCanDoRefresh(PtrFrameLayout frame, View content, View header) {
                return true;
            }

            // 重新整理開始會執行該方法
            @Override
            public void onRefreshBegin(PtrFrameLayout frame) {
                // 這裡做一些重新整理操作
                // Refresh();

                // 用於關閉下拉重新整理
                ptr_frame.refreshComplete();
            }
        });
         **/


        /**
         * 不用判斷什麼時候重新整理和載入,方法裡有自己的判斷,適合大多數的情況
         */
        ptr_frame.setPtrHandler(new PtrDefaultHandler2() {
            // 載入更多開始會執行該方法
            @Override
            public void onLoadMoreBegin(PtrFrameLayout frame) {
                // 這裡做一些載入的操作
                // LoadMore();

                // 用於關閉上拉載入
                ptr_frame.refreshComplete();
            }

            // 重新整理開始會執行該方法
            @Override
            public void onRefreshBegin(PtrFrameLayout frame) {
                // 這裡做一些重新整理操作
                // Refresh();

                // 用於關閉下拉重新整理
                ptr_frame.refreshComplete();
            }
        });

    }
}

上面的程式碼我就不詳細解釋了,註釋很詳細,大家去實現一次就會更加熟悉。多使用吧!

==================================

每天進步一點點!加油!