转载请标明出处:
http://blog.csdn.net/xuehuayous/article/details/50394640
本文出自:【Kevin.zhou的博客】
一、 闲扯
我们在《PullToRefresh 分析之二、UI结构》提到刷新加载的样式默认的两种样式如下:
、
但是我们的需求或许是这样的:
那么如果是这样的会不会使用户体验更好些,当然这不是我们开发人员能决定的,但是我们还是要掌握快速定制出这些动画的方法的。其实一个复杂的动画都是一系列简单动作的集合。
通过分析,这些动画其实正是和我们刷新加载的几个状态相对应:
二、 样式扩展基类封装
基于以上分析,我们只要把几个关键的时间点回调出来,让大家去自己定义自己的样式就可以了。这里我写了个LoadingLayoutBase基类,然后该类有一些抽象方法,只要继承了该基类实现方法,就可以啦。由于修改PullToRefresh框架的地方还是比较多的,最后会给大家提供源码,大家可以自己看下还是比较简单的。这里只是讲下如何使用。
下面以京东商城为例进行说明如何扩展,当然美团和汽车之家的扩展也会给大家提供源码的。
(一)、扩展京东样式
1、继承LoadingLayoutBase,实现抽象方法
大家可以把"Copy JavaDoc"勾选上,这样就是把说明也添加过来。
2. 实现父类构造函数
我们在最后使用的时候是通过代码new 对象的方式创建实例,这里只实现带有Context的构造函数就可以了。
现在我们得到了一个架子:
-
-
-
- public class JingDongHeaderLayout extends LoadingLayoutBase{
- public JingDongHeaderLayout(Context context) {
- super(context);
- }
-
-
-
-
-
-
- @Override
- public int getContentSize() {
- return 0;
- }
-
-
-
-
- @Override
- public void pullToRefresh() {
-
- }
-
-
-
-
- @Override
- public void releaseToRefresh() {
-
- }
-
-
-
-
-
-
- @Override
- public void onPull(float scaleOfLayout) {
-
- }
-
-
-
-
-
- @Override
- public void refreshing() {
-
- }
-
-
-
-
- @Override
- public void reset() {
-
- }
-
-
-
-
-
-
-
- @Override
- public void setPullLabel(CharSequence pullLabel) {
-
- }
-
-
-
-
-
-
-
- @Override
- public void setRefreshingLabel(CharSequence refreshingLabel) {
-
- }
-
-
-
-
-
-
-
-
- @Override
- public void setReleaseLabel(CharSequence releaseLabel) {
-
- }
- }
看起来一大坨还是不少的,其实就如下几个方法,然后给大家写成人话:
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;
-
-
- 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. 下拉过程动画编写
我们再把效果图拿过来研究下:
可以发现在下拉的时候的动画比较简单,就是京东小哥和包裹都由小变大。我们就想到要在下拉开始的回调以及下拉过程的回调中去写。
-
- @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);
四、源码
另外,欢迎 star or f**k me on github!
五、结语
在该篇中,我们通过修改PullToRefresh框架实现了简单扩展刷新加载头部尾部的样式配置。那么关于PullToRefresh的五篇文章就完结啦。