天天看點

Android PullToRefresh 分析之五、擴充重新整理加載樣式一、 閑扯二、 樣式擴充基類封裝三、設定自定義樣式四、源碼五、結語

轉載請标明出處:

http://blog.csdn.net/xuehuayous/article/details/50394640

本文出自:【Kevin.zhou的部落格】

前言:接着上 一篇 《Android PullToRefresh 分析之四、擴充RecyclerView》 ,這一篇主要分析如何擴充重新整理加載樣式,來建立各式各樣的重新整理加載效果。

一、 閑扯

          我們在《PullToRefresh 分析之二、UI結構》提到重新整理加載的樣式預設的兩種樣式如下:

Android PullToRefresh 分析之五、擴充重新整理加載樣式一、 閑扯二、 樣式擴充基類封裝三、設定自定義樣式四、源碼五、結語

Android PullToRefresh 分析之五、擴充重新整理加載樣式一、 閑扯二、 樣式擴充基類封裝三、設定自定義樣式四、源碼五、結語

    但是我們的需求或許是這樣的:

Android PullToRefresh 分析之五、擴充重新整理加載樣式一、 閑扯二、 樣式擴充基類封裝三、設定自定義樣式四、源碼五、結語
Android PullToRefresh 分析之五、擴充重新整理加載樣式一、 閑扯二、 樣式擴充基類封裝三、設定自定義樣式四、源碼五、結語
Android PullToRefresh 分析之五、擴充重新整理加載樣式一、 閑扯二、 樣式擴充基類封裝三、設定自定義樣式四、源碼五、結語

    那麼如果是這樣的會不會使使用者體驗更好些,當然這不是我們開發人員能決定的,但是我們還是要掌握快速定制出這些動畫的方法的。其實一個複雜的動畫都是一系列簡單動作的集合。     通過分析,這些動畫其實正是和我們重新整理加載的幾個狀态相對應:

Android PullToRefresh 分析之五、擴充重新整理加載樣式一、 閑扯二、 樣式擴充基類封裝三、設定自定義樣式四、源碼五、結語

二、 樣式擴充基類封裝

         基于以上分析,我們隻要把幾個關鍵的時間點回調出來,讓大家去自己定義自己的樣式就可以了。這裡我寫了個LoadingLayoutBase基類,然後該類有一些抽象方法,隻要繼承了該基類實作方法,就可以啦。由于修改PullToRefresh架構的地方還是比較多的,最後會給大家提供源碼,大家可以自己看下還是比較簡單的。這裡隻是講下如何使用。     下面以京東商城為例進行說明如何擴充,當然美團和汽車之家的擴充也會給大家提供源碼的。

(一)、擴充京東樣式

1、繼承LoadingLayoutBase,實作抽象方法

Android PullToRefresh 分析之五、擴充重新整理加載樣式一、 閑扯二、 樣式擴充基類封裝三、設定自定義樣式四、源碼五、結語

    大家可以把"Copy JavaDoc"勾選上,這樣就是把說明也添加過來。

2. 實作父類構造函數

Android PullToRefresh 分析之五、擴充重新整理加載樣式一、 閑扯二、 樣式擴充基類封裝三、設定自定義樣式四、源碼五、結語

    我們在最後使用的時候是通過代碼new 對象的方式建立執行個體,這裡隻實作帶有Context的構造函數就可以了。     現在我們得到了一個架子:

/**
 * Created by zhouwk on 2015/12/24 0024.
 */
public class JingDongHeaderLayout extends LoadingLayoutBase{
    public JingDongHeaderLayout(Context context) {
        super(context);
    }

    /**
     * get the LoadingLayout height or width
     *
     * @return size
     */
    @Override
    public int getContentSize() {
        return 0;
    }

    /**
     * Call when the widget begins to slide
     */
    @Override
    public void pullToRefresh() {

    }

    /**
     * Call when the LoadingLayout is fully displayed
     */
    @Override
    public void releaseToRefresh() {

    }

    /**
     * Call when the LoadingLayout is sliding
     *
     * @param scaleOfLayout scaleOfLayout
     */
    @Override
    public void onPull(float scaleOfLayout) {

    }

    /**
     * Call when the LoadingLayout is fully displayed and the widget has released.
     * Used to prompt the user loading data
     */
    @Override
    public void refreshing() {

    }

    /**
     * Call when the data has loaded
     */
    @Override
    public void reset() {

    }

    /**
     * Set Text to show when the Widget is being Pulled
     * <code>setPullLabel(releaseLabel, Mode.BOTH)</code>
     *
     * @param pullLabel - CharSequence to display
     */
    @Override
    public void setPullLabel(CharSequence pullLabel) {

    }

    /**
     * Set Text to show when the Widget is refreshing
     * <code>setRefreshingLabel(releaseLabel, Mode.BOTH)</code>
     *
     * @param refreshingLabel - CharSequence to display
     */
    @Override
    public void setRefreshingLabel(CharSequence refreshingLabel) {

    }

    /**
     * Set Text to show when the Widget is being pulled, and will refresh when
     * released. This is the same as calling
     * <code>setReleaseLabel(releaseLabel, Mode.BOTH)</code>
     *
     * @param releaseLabel - CharSequence to display
     */
    @Override
    public void setReleaseLabel(CharSequence releaseLabel) {

    }
}
           

看起來一大坨還是不少的,其實就如下幾個方法,然後給大家寫成人話:

Android PullToRefresh 分析之五、擴充重新整理加載樣式一、 閑扯二、 樣式擴充基類封裝三、設定自定義樣式四、源碼五、結語

3. 寫"加載頭部"布局

<?xml version="1.0" encoding="utf-8"?>
<merge xmlns:android="http://schemas.android.com/apk/res/android" >

    <FrameLayout
        android:id="@+id/fl_inner"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:paddingBottom="@dimen/header_footer_top_bottom_padding"
        android:paddingLeft="@dimen/header_footer_left_right_padding"
        android:paddingRight="@dimen/header_footer_left_right_padding"
        android:paddingTop="@dimen/header_footer_top_bottom_padding" >

        <LinearLayout
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_gravity="center"
            android:gravity="center_horizontal"
            android:orientation="vertical" >

            <TextView
                android:id="@+id/pull_to_refresh_text"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:singleLine="true"
                android:text="讓購物更便捷"
                android:textColor="#5b5b5b"
                android:textAppearance="?android:attr/textAppearance" />

            <TextView
                android:id="@+id/pull_to_refresh_sub_text"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:singleLine="true"
                android:text="下拉重新整理"
                android:textColor="#5b5b5b"
                android:textAppearance="?android:attr/textAppearanceSmall"/>
        </LinearLayout>

        <RelativeLayout
            android:layout_width="match_parent"
            android:layout_height="match_parent">

            <ImageView
                android:id="@+id/pull_to_refresh_people"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:layout_marginLeft="40dp"
                android:src="@mipmap/app_refresh_people_0" />

            <ImageView
                android:id="@+id/pull_to_refresh_goods"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:layout_alignRight="@id/pull_to_refresh_people"
                android:layout_centerVertical="true"
                android:src="@mipmap/app_refresh_goods_0" />

        </RelativeLayout>

    </FrameLayout>

</merge>
           

布局比較簡單,效果是這樣的:

Android PullToRefresh 分析之五、擴充重新整理加載樣式一、 閑扯二、 樣式擴充基類封裝三、設定自定義樣式四、源碼五、結語

4. 初始化布局視圖

public JingDongHeaderLayout(Context context) {
	super(context);

	LayoutInflater.from(context).inflate(R.layout.jingdong_header_loadinglayout, this);

	mInnerLayout = (FrameLayout) findViewById(R.id.fl_inner);
	mHeaderText = (TextView) mInnerLayout.findViewById(R.id.pull_to_refresh_text);
	mSubHeaderText = (TextView) mInnerLayout.findViewById(R.id.pull_to_refresh_sub_text);
	mGoodsImage = (ImageView) mInnerLayout.findViewById(R.id.pull_to_refresh_goods);
	mPersonImage = (ImageView) mInnerLayout.findViewById(R.id.pull_to_refresh_people);

	LayoutParams lp = (LayoutParams) mInnerLayout.getLayoutParams();
	lp.gravity = Gravity.BOTTOM;

	// Load in labels
	mPullLabel = context.getString(R.string.jingdong_pull_label);
	mRefreshingLabel = context.getString(R.string.jingdong_refreshing_label);
	mReleaseLabel = context.getString(R.string.jingdong_release_label);

	reset();
}
           

    大家要注意的是初始化布局,"重新整理頭部"的時候要加上這個:

LayoutParams lp = (LayoutParams) mInnerLayout.getLayoutParams();
lp.gravity = Gravity.BOTTOM;
           

如果是"加載尾部",就是這樣的:

LayoutParams lp = (LayoutParams) mInnerLayout.getLayoutParams();
lp.gravity = Gravity.TOP;
           

5. 設定"加載頭部"高度

// 擷取"加載頭部"高度
@Override
public int getContentSize() {
	return mInnerLayout.getHeight();
}
           

6. 下拉過程動畫編寫          我們再把效果圖拿過來研究下:

Android PullToRefresh 分析之五、擴充重新整理加載樣式一、 閑扯二、 樣式擴充基類封裝三、設定自定義樣式四、源碼五、結語

    可以發現在下拉的時候的動畫比較簡單,就是京東小哥和包裹都由小變大。我們就想到要在下拉開始的回調以及下拉過程的回調中去寫。

// 開始下拉時的回調
@Override
public void pullToRefresh() {
    mSubHeaderText.setText(mPullLabel);
}
           
// 下拉拖動時的回調
@Override
public void onPull(float scaleOfLayout) {
    scaleOfLayout = scaleOfLayout > 1.0f ? 1.0f : scaleOfLayout;

    if (mGoodsImage.getVisibility() != View.VISIBLE) {
        mGoodsImage.setVisibility(View.VISIBLE);
    }

    //透明度動畫
    ObjectAnimator animAlphaP = ObjectAnimator.ofFloat(mPersonImage, "alpha", -1, 1).setDuration(300);
    animAlphaP.setCurrentPlayTime((long) (scaleOfLayout * 300));
    ObjectAnimator animAlphaG = ObjectAnimator.ofFloat(mGoodsImage, "alpha", -1, 1).setDuration(300);
    animAlphaG.setCurrentPlayTime((long) (scaleOfLayout * 300));

    //縮放動畫
    ViewHelper.setPivotX(mPersonImage, 0);  // 設定中心點
    ViewHelper.setPivotY(mPersonImage, 0);
    ObjectAnimator animPX = ObjectAnimator.ofFloat(mPersonImage, "scaleX", 0, 1).setDuration(300);
    animPX.setCurrentPlayTime((long) (scaleOfLayout * 300));
    ObjectAnimator animPY = ObjectAnimator.ofFloat(mPersonImage, "scaleY", 0, 1).setDuration(300);
    animPY.setCurrentPlayTime((long) (scaleOfLayout * 300));

    ViewHelper.setPivotX(mGoodsImage, mGoodsImage.getMeasuredWidth());
    ObjectAnimator animGX = ObjectAnimator.ofFloat(mGoodsImage, "scaleX", 0, 1).setDuration(300);
    animGX.setCurrentPlayTime((long) (scaleOfLayout * 300));
    ObjectAnimator animGY = ObjectAnimator.ofFloat(mGoodsImage, "scaleY", 0, 1).setDuration(300);
    animGY.setCurrentPlayTime((long) (scaleOfLayout * 300));
}
           

看着代碼很多,其實思路非常簡單,就是設定變大的動畫随着拖動的距離大小變化,這裡用到了nineoldandroids這個動畫相容庫。

 7. "加載頭部"完全顯示時更改提示顯示

    我們發現開始的提示是"下拉可以重新整理"後來變為了"松開可以重新整理",這個的設定就是在 "加載頭部"完全顯示的回調中設定的。

// "加載頭部"完全顯示時的回調
@Override
public void releaseToRefresh() {
    mSubHeaderText.setText(mReleaseLabel);
}
           

8. 正在加載的設定

    手指釋放後,我們看到一個京東小哥在飛奔,就是在 釋放後重新整理時的回調 中設定的。

// 釋放後重新整理時的回調
@Override
public void refreshing() {
    mSubHeaderText.setText(mRefreshingLabel);

    if (animP == null) {
        mPersonImage.setImageResource(R.drawable.refreshing_anim);
        animP = (AnimationDrawable) mPersonImage.getDrawable();
    }
    animP.start();
    if (mGoodsImage.getVisibility() == View.VISIBLE) {
        mGoodsImage.setVisibility(View.INVISIBLE);
    }
}
           

    這裡我們使用的是幀動畫,就是幾張圖檔刷啊刷,給人的假象就是京東小哥正在賣力跑。

9. 初始化到未重新整理狀态

// 初始化到未重新整理狀态
@Override
public void reset() {
    if (animP != null) {
        animP.stop();
        animP = null;
    }
    mPersonImage.setImageResource(R.mipmap.app_refresh_people_0);
    if (mGoodsImage.getVisibility() == View.VISIBLE) {
        mGoodsImage.setVisibility(View.INVISIBLE);
    }
}
           

就是把我們加載時的動畫關掉。

10. 設定提示

@Override
public void setPullLabel(CharSequence pullLabel) {
    mPullLabel = pullLabel;
}

@Override
public void setRefreshingLabel(CharSequence refreshingLabel) {
    mRefreshingLabel = refreshingLabel;
}

@Override
public void setReleaseLabel(CharSequence releaseLabel) {
    mReleaseLabel = releaseLabel;
}
           

這三個方法不實作也可以,因為我們是通過以下方式初始提示的

mPullLabel = context.getString(R.string.jingdong_pull_label);
mRefreshingLabel = context.getString(R.string.jingdong_refreshing_label);
mReleaseLabel = context.getString(R.string.jingdong_release_label);
           

之是以抽象出來這三個方法,是可以讓大家更靈活地改變提示語。

三、設定自定義樣式

    一行代碼搞定

mPullToRefreshRecyclerView.setHeaderLayout(new JingDongHeaderLayout(this));
           

當然也可以設定底部樣式:

mPullToRefreshRecyclerView.setFooterLayout(xxx);
           

四、源碼

    給大家提供一個github的位址:PullToRefresh-demo     另外,歡迎 star or f**k me on github!

Android PullToRefresh 分析之五、擴充重新整理加載樣式一、 閑扯二、 樣式擴充基類封裝三、設定自定義樣式四、源碼五、結語

五、結語

         在該篇中,我們通過修改PullToRefresh架構實作了簡單擴充重新整理加載頭部尾部的樣式配置。那麼關于PullToRefresh的五篇文章就完結啦。