快速仿寫京東、天貓下拉刷新

很久沒輸出文章了,最近研發任務比較忙,果真計劃趕不上變化,以前還但願能一週一輸出,好吧,我仍是認可本身比較懶好了,=.=## 此次跟你們分享一下下拉刷新,以前咱們的公司的項目一直都是使用SwipeRefreshLayout,官方的Md風格,好用少Bug。閒話很少說了,我們如今分析一下哪一種下拉刷新比較多,有的是直接包在ListView或者RecyclerView的頭部,有得則是像SwipeRefreshLayout同樣,包在視圖的最外層,我的建議使用包在最外層的作法,可擴展性比較強,另外一種的話,能夠借鑑一下XRecyclerView,具體的就很少說了,我們使用最外層的方法,快速的構建一個相似像京東、天貓的下拉刷新。

1.使用框架android-Ultra-Pull-To-Refresh

https://github.com/liaohuqiu/android-Ultra-Pull-To-Refreshandroid

你們感興趣的能夠去看一下這個下拉刷新框架,很是強大,可擴展性很是強,兼容各類view的下拉刷新事件。git

2.京東下拉刷新

先放一張效果來看一下,京東的下拉刷新動畫:github

jd_origin.gif

通俗的來講,就是一個快遞小哥,跑過來,接住商品,而後刷新的時候,本身拿着商品跑起來。(解釋有點牽強啊) 我們來分析一下整一個過程: 1.快遞小哥從遠處跑過去拿商品,能夠拆成兩個部分.bash

Paste_Image.png

當拿到商品以後,就跑起來,在咱們程序裏,就是動畫:框架

Paste_Image.png

(你去解壓一下京東的apk,你也能拿到這些圖片)ide

其實就是圖片之間的切換,以上的準備工做都完成了,看看這個xml應該怎麼寫:佈局

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="wrap_content">


    <FrameLayout
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_toLeftOf="@+id/layout_tx">

        <ImageView
            android:id="@+id/iv_man"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:background="@mipmap/a2a" />

        <ImageView
            android:id="@+id/iv_goods"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_gravity="right|center"
            android:src="@mipmap/a29" />
    </FrameLayout>

    <LinearLayout
        android:id="@+id/layout_tx"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_centerInParent="true"
        android:layout_marginLeft="5dp"
        android:gravity="center_vertical"
        android:orientation="vertical"
        android:padding="5dp">

        <TextView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="讓購物更便捷"
            android:textSize="14sp" />

        <TextView
            android:id="@+id/tv_remain"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_marginTop="5dp"
            android:text="鬆開刷新"
            android:textSize="12sp" />
    </LinearLayout>


</RelativeLayout>
複製代碼

根據第一我的跟商品,我們先分開兩個ImageView,使用FrameLayout佈局,而後讓這兩個ImageView放進去,商品的這個ImageView設置layoutgravity=right.字體

我們再看看android-Ultra-Pull-To-Refresh這個框架給咱們帶來什麼。動畫

public interface PtrUIHandler {

    /**
     * When the content view has reached top and refresh has been completed, view will be reset.
     *
     * @param frame
     */
    public void onUIReset(PtrFrameLayout frame);

    /**
     * prepare for loading
     *
     * @param frame
     */
    public void onUIRefreshPrepare(PtrFrameLayout frame);

    /**
     * perform refreshing UI
     */
    public void onUIRefreshBegin(PtrFrameLayout frame);

    /**
     * perform UI after refresh
     */
    public void onUIRefreshComplete(PtrFrameLayout frame);

    public void onUIPositionChange(PtrFrameLayout frame, boolean isUnderTouch, byte status, PtrIndicator ptrIndicator);
}
複製代碼

這是一下下拉刷新事件的接口,只要實現以上接口就能獲得相應的,獲得以上接口ui

至於各個接口有什麼,看接口名你們應該就知道了。 直接貼代碼更直觀:

/**
 * 下拉刷新header
 * Created by shenminjie on 2016/12/6.
 */
public class JdRefreshHeader extends FrameLayout implements PtrUIHandler {

    /**
     * 提醒文本
     */
    private TextView mTvRemind;

    /**
     * 快遞員logo
     */
    private ImageView mIvMan;

    /**
     * 商品logo
     */
    private ImageView mIvGoods;

    /**
     * 狀態識別
     */
    private int mState;

    /**
     * 重置
     * 準備刷新
     * 開始刷新
     * 結束刷新
     */
    public static final int STATE_RESET = -1;
    public static final int STATE_PREPARE = 0;
    public static final int STATE_BEGIN = 1;
    public static final int STATE_FINISH = 2;

    public static final int MARGIN_RIGHT = 100;

    /**
     * 動畫
     */
    private AnimationDrawable mAnimation;


    public JdRefreshHeader(Context context) {
        super(context);
        initView();
    }

    public JdRefreshHeader(Context context, AttributeSet attrs) {
        super(context, attrs);
        initView();
    }

    public JdRefreshHeader(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        initView();
    }

    /**
     * 初始化view
     */
    private void initView() {
        View view = LayoutInflater.from(getContext()).inflate(R.layout.jd_refresh_header_view, this, false);
        mTvRemind = (TextView) view.findViewById(R.id.tv_remain);
        mIvMan = (ImageView) view.findViewById(R.id.iv_man);
        mIvGoods = (ImageView) view.findViewById(R.id.iv_goods);
        addView(view);

    }


    @Override
    public void onUIReset(PtrFrameLayout frame) {
        mState = STATE_RESET;
    }

    @Override
    public void onUIRefreshPrepare(PtrFrameLayout frame) {
        mState = STATE_PREPARE;
    }

    @Override
    public void onUIRefreshBegin(PtrFrameLayout frame) {
        mState = STATE_BEGIN;
        //隱藏商品logo,開啓跑步動畫
        mIvGoods.setVisibility(View.GONE);
        mIvMan.setBackgroundResource(R.drawable.runningman);
        mAnimation = (AnimationDrawable) mIvMan.getBackground();
        if (!mAnimation.isRunning()) {
            mAnimation.start();
        }
    }

    @Override
    public void onUIRefreshComplete(PtrFrameLayout frame) {
        mState = STATE_FINISH;
        mIvGoods.setVisibility(View.VISIBLE);
        //中止動畫
        if (mAnimation.isRunning()) {
            mAnimation.stop();
        }
        mIvMan.setBackgroundResource(R.mipmap.a2a);
    }

    @Override
    public void onUIPositionChange(PtrFrameLayout frame, boolean isUnderTouch, byte status, PtrIndicator ptrIndicator) {
        //處理提醒字體
        switch (mState) {
            case STATE_PREPARE:
                //logo設置
                mIvMan.setAlpha(ptrIndicator.getCurrentPercent());
                mIvGoods.setAlpha(ptrIndicator.getCurrentPercent());
                FrameLayout.LayoutParams mIvManLayoutParams = (LayoutParams) mIvMan.getLayoutParams();
                if (ptrIndicator.getCurrentPercent() <= 1) {
                    mIvMan.setScaleX(ptrIndicator.getCurrentPercent());
                    mIvMan.setScaleY(ptrIndicator.getCurrentPercent());
                    mIvGoods.setScaleX(ptrIndicator.getCurrentPercent());
                    mIvGoods.setScaleY(ptrIndicator.getCurrentPercent());
                    int marginRight = (int) (MARGIN_RIGHT - MARGIN_RIGHT * ptrIndicator.getCurrentPercent());
                    mIvManLayoutParams.setMargins(0, 0, marginRight, 0);
                    mIvMan.setLayoutParams(mIvManLayoutParams);
                }
                if (ptrIndicator.getCurrentPercent() < 1.2) {
                    mTvRemind.setText("下拉刷新...");
                } else {
                    mTvRemind.setText("鬆開刷新...");
                }
                break;
            case STATE_BEGIN:
                mTvRemind.setText("更新中...");
                break;
            case STATE_FINISH:
                mTvRemind.setText("加載完成...");
                break;
        }
    }
}
複製代碼

建立一個成員變量mState,用於保存下拉刷新的時候,每個狀態,而後根據保存好的狀態在UiPositionChange的接口中,對UI進行相應的修改,保存每一個狀態文本的提示,在下拉的過程當中,經過UiPositionChange的回調,獲取PtrIndicator中,能夠獲取下拉的百分比,根據這個百分比咱們能夠作不少東西,例如京東的快遞小哥從遠處跑過來拿商品,以及快遞小哥與商品之間的大小,均可以根據這個PtrIndicator百分比進行設置其大小的比例,跑過來這個過程我使用的方法是利用marginRight進行設置二者之間的距離,當達到下拉刷新的臨界點時,快遞小哥跟商品之間的margin爲0,達到了快遞小哥獲取商品的效果,而後當刷新的時候,隱藏商品,使用以前所提供的三張圖片進行效應的切換,也就是動畫:

<animation-list xmlns:android="http://schemas.android.com/apk/res/android" android:oneshot="false">
    <item
        android:drawable="@mipmap/a2b"
        android:duration="70" />
    <item
        android:drawable="@mipmap/a2c"
        android:duration="70" />
    <item
        android:drawable="@mipmap/a2d"
        android:duration="70" />
</animation-list>
複製代碼
@Override
public void onUIRefreshBegin(PtrFrameLayout frame) {
    mState = STATE_BEGIN;
    //隱藏商品logo,開啓跑步動畫
    mIvGoods.setVisibility(View.GONE);
    mIvMan.setBackgroundResource(R.drawable.runningman);
    mAnimation = (AnimationDrawable) mIvMan.getBackground();
    if (!mAnimation.isRunning()) {
        mAnimation.start();
    }
}

複製代碼

當刷新結束的時候,咱們把動畫中止,並把以前的商品顯示出來:

@Override
public void onUIRefreshComplete(PtrFrameLayout frame) {
    mState = STATE_FINISH;
    mIvGoods.setVisibility(View.VISIBLE);
    //中止動畫
    if (mAnimation.isRunning()) {
        mAnimation.stop();
    }
    mIvMan.setBackgroundResource(R.mipmap.a2a);
}

複製代碼

很簡單,基本上難點框架都已經幫咱們封裝好了,咱們只要繼承PtrFrameLayout,添加相應的Header以及實現PtrUIHandler就能夠實現。

/**
 *仿京東下拉刷新
 * Created by shenminjie on 2016/12/6.
 */

public class JdRefreshLayout extends PtrFrameLayout {

    /**
     * headerView
     */
     JdRefreshHeader mHeaderView;

    public JdRefreshLayout(Context context) {
        super(context);
        initView();
    }

    public JdRefreshLayout(Context context, AttributeSet attrs) {
        super(context, attrs);
        initView();
    }

    public JdRefreshLayout(Context context, AttributeSet attrs, int defStyle) {
        super(context, attrs, defStyle);
        initView();
    }


    /**
     * 初始化view
     */
    private void initView() {
        mHeaderView = new JdRefreshHeader(getContext());
        setHeaderView(mHeaderView);
        addPtrUIHandler(mHeaderView);
    }


}
複製代碼

my_jd.gif

二、天貓

天貓的更簡單,毫無動畫可言,說白了就是個GIF,你們能夠去下載個apk,解壓後能獲得其gif。 原理跟以前的是同樣,但這裏我使用的是fresco進行加載gif,方法有不少,你們感興趣的能夠去試試。

tmall_origin.gif

/**
 * 下拉刷新header
 * Created by shenminjie on 2016/12/6.
 */
public class TmallRefreshHeader extends FrameLayout implements PtrUIHandler {

    /**
     * 提醒文本
     */
    private TextView mTvRemind;


    /**
     * 狀態識別
     */
    private int mState;

    /**
     * 重置
     * 準備刷新
     * 開始刷新
     * 結束刷新
     */
    public static final int STATE_RESET = -1;
    public static final int STATE_PREPARE = 0;
    public static final int STATE_BEGIN = 1;
    public static final int STATE_FINISH = 2;


    public TmallRefreshHeader(Context context) {
        super(context);
        initView();
    }

    public TmallRefreshHeader(Context context, AttributeSet attrs) {
        super(context, attrs);
        initView();
    }

    public TmallRefreshHeader(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        initView();
    }

    /**
     * 初始化view
     */
    private void initView() {
        View view = LayoutInflater.from(getContext()).inflate(R.layout.tmall_refresh_header_view, this, false);
        mTvRemind = (TextView) view.findViewById(R.id.tv_remind);
        SimpleDraweeView sdv = (SimpleDraweeView) view.findViewById(R.id.tm_logo);
        DraweeController mDraweeController = Fresco.newDraweeControllerBuilder()
                .setAutoPlayAnimations(true)
                //設置uri,加載本地的gif資源
                .setUri(Uri.parse("res://" + getContext().getPackageName() + "/" + R.drawable.tm_mui_bike))//設置uri
                .build();
        sdv.setController(mDraweeController);
        addView(view);
    }


    @Override
    public void onUIReset(PtrFrameLayout frame) {
        mState = STATE_RESET;
    }

    @Override
    public void onUIRefreshPrepare(PtrFrameLayout frame) {
        mState = STATE_PREPARE;
    }

    @Override
    public void onUIRefreshBegin(PtrFrameLayout frame) {
        mState = STATE_BEGIN;
    }

    @Override
    public void onUIRefreshComplete(PtrFrameLayout frame) {
        mState = STATE_FINISH;
    }

    @Override
    public void onUIPositionChange(PtrFrameLayout frame, boolean isUnderTouch, byte status, PtrIndicator ptrIndicator) {
        //處理提醒字體
        switch (mState) {
            case STATE_PREPARE:
                if (ptrIndicator.getCurrentPercent() < 1) {
                    mTvRemind.setText("下拉刷新");
                } else {
                    mTvRemind.setText("鬆開當即刷新");
                }
                break;
            case STATE_BEGIN:
                mTvRemind.setText("正在刷新...");
                break;
            case STATE_FINISH:
                mTvRemind.setText("加載完成...");
                break;
        }
    }
}

/**
 * 仿天貓下拉刷新view
 * Created by shenminjie on 2016/12/6.
 */

public class TmallRefreshLayout extends PtrFrameLayout {

    /**
     * headerView
     */
     TmallRefreshHeader mHeaderView;

    public TmallRefreshLayout(Context context) {
        super(context);
        initView();
    }

    public TmallRefreshLayout(Context context, AttributeSet attrs) {
        super(context, attrs);
        initView();
    }

    public TmallRefreshLayout(Context context, AttributeSet attrs, int defStyle) {
        super(context, attrs, defStyle);
        initView();
    }


    /**
     * 初始化view
     */
    private void initView() {
        mHeaderView = new TmallRefreshHeader(getContext());
        setHeaderView(mHeaderView);
        addPtrUIHandler(mHeaderView);
    }


}
複製代碼

my_tmall.gif

github:

https://github.com/shenminjie/jd_tmall_refresh_demo

相關文章
相關標籤/搜索