转载请标明出处:
http://blog.csdn.net/xuehuayous/article/details/50394640
本文出自:【Kevin.zhou的博客】

前言:接着上 一篇 《Android PullToRefresh分析之四、扩展RecyclerView ,这一篇主要分析如何扩展刷新加载样式,来创建各式各样的刷新加载效果。

一、 闲扯

我们在《PullToRefresh分析之二、UI结构》提到刷新加载的样式默认的两种样式如下:
但是我们的需求或许是这样的:





那么如果是这样的会不会使用户体验更好些,当然这不是我们开发人员能决定的,但是我们还是要掌握快速定制出这些动画的方法的。其实一个复杂的动画都是一系列简单动作的集合。 通过分析,这些动画其实正是和我们刷新加载的几个状态相对应: Android PullToRefresh 分析之五、扩展刷新加载样式_第1张图片

二、 样式扩展基类封装

基于以上分析,我们只要把几个关键的时间点回调出来,让大家去自己定义自己的样式就可以了。这里我写了个LoadingLayoutBase基类,然后该类有一些抽象方法,只要继承了该基类实现方法,就可以啦。由于修改PullToRefresh框架的地方还是比较多的,最后会给大家提供源码,大家可以自己看下还是比较简单的。这里只是讲下如何使用。 下面以京东商城为例进行说明如何扩展,当然美团和汽车之家的扩展也会给大家提供源码的。

(一)、扩展京东样式

1、继承LoadingLayoutBase,实现抽象方法
Android PullToRefresh 分析之五、扩展刷新加载样式_第2张图片

大家可以把"Copy JavaDoc"勾选上,这样就是把说明也添加过来。
2. 实现父类构造函数
Android PullToRefresh 分析之五、扩展刷新加载样式_第3张图片

我们在最后使用的时候是通过代码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 分析之五、扩展刷新加载样式_第4张图片

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>
布局比较简单,效果是这样的:

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 labelsmPullLabel = 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. 设置"加载头部"高度

// 获取"加载头部"高度@Overridepublic int getContentSize() {return mInnerLayout.getHeight();}

6. 下拉过程动画编写 我们再把效果图拿过来研究下: Android PullToRefresh 分析之五、扩展刷新加载样式_第5张图片
可以发现在下拉的时候的动画比较简单,就是京东小哥和包裹都由小变大。我们就想到要在下拉开始的回调以及下拉过程的回调中去写。
// 开始下拉时的回调@Overridepublic void pullToRefresh() {    mSubHeaderText.setText(mPullLabel);}

// 下拉拖动时的回调@Overridepublic 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. "加载头部"完全显示时更改提示显示
我们发现开始的提示是"下拉可以刷新"后来变为了"松开可以刷新",这个的设置就是在 "加载头部"完全显示的回调中设置的。
// "加载头部"完全显示时的回调@Overridepublic void releaseToRefresh() {    mSubHeaderText.setText(mReleaseLabel);}

8. 正在加载的设置
手指释放后,我们看到一个京东小哥在飞奔,就是在释放后刷新时的回调 中设置的。
// 释放后刷新时的回调@Overridepublic 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. 初始化到未刷新状态
// 初始化到未刷新状态@Overridepublic 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. 设置提示
@Overridepublic void setPullLabel(CharSequence pullLabel) {    mPullLabel = pullLabel;}@Overridepublic void setRefreshingLabel(CharSequence refreshingLabel) {    mRefreshingLabel = refreshingLabel;}@Overridepublic 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!

五、结语

在该篇中,我们通过修改PullToRefresh框架实现了简单扩展刷新加载头部尾部的样式配置。那么关于PullToRefresh的五篇文章就完结啦。

更多相关文章

  1. Android RadioButton的自定义样式
  2. 自定义RatingBar的样式
  3. Android的Activity加载方式实例分析
  4. android使用PullToRefresh框架实现ListView下拉刷新上拉加载更多
  5. 通过查看系统的ProgressBar样式来自定义旋转动画
  6. Android学习笔记-Android非布局activity中布局文件及控件加载方
  7. Android图片加载框架Picasso最全使用教程 一

随机推荐

  1. android jni开发,用javah生成***.h头文件,
  2. Android学习2
  3. - Android深入浅出Binder机制
  4. Android(安卓)Studio快捷键(3) 代码提示
  5. Android命令生成编译出build.xml文件
  6. Android非正常结束时的生命周期
  7. XE5 Android(安卓)开发实现手机打电话和
  8. Android中获取字符串长度、宽度(所占像素
  9. Android:webView加载h5网页视频,播放不了,以
  10. android 桌面组件 App widget的使用