Android仿京東到家下拉刷新

項目地址:https://github.com/TaoPaox/TpTools

公司的項目需要用到類似京東到家的下拉刷新,閑來無聊的時候研究一下,框架用的是 SmartRefreshLayout

先上圖(錄屏軟件有點卡):

仿京東到家下拉刷新

一州叠、分析

京東到家的下拉加載動畫初看挺簡單的鹿响,一共有三個狀態(tài)。

  • 1只酥、剛開始下拉的時候娃胆,小車從小變大的過程遍希。
  • 2、下拉到一定程度松手,小車開始顯示不停抖動的動畫
  • 3里烦、刷新結(jié)束的前400毫秒凿蒜,小車要從左往右移動出去禁谦。

二、反編譯App看實現(xiàn)原理

反編譯雖然源碼看不太清,但是我們可以拿到他用到的圖片資源


圖片動畫資源

看到圖片后知道原來它用的是最普通的幀動畫啊废封,也不是太復雜州泊。
拿到資源圖片,知道實現(xiàn)原理漂洋,就開工吧遥皂!

三、實現(xiàn)動畫效果

首先自定義View MyRefreshHeader繼承自 LinearLayout刽漂,并實現(xiàn) SmartRefreshLayoutRefreshHeader 接口演训。
然后主要就是重寫 RefreshHeader 接口中的方法,里面提供了下拉刷新時不同階段的回調(diào)贝咙,找到對應的方法碼代碼就好样悟。

邏輯主要在 onStateChanged()方法里,代碼中注釋寫的很詳細庭猩。
切換狀態(tài)原理是每次都給 ImageView 設(shè)置對應的資源圖片或動畫文件窟她,然后得到 AnimationDrawable 開啟動畫

需要注意的是:當我們刷新完成的時候,需要延時400毫秒關(guān)閉刷新界面來顯示小車平移的動畫,這就需要在onFinish方法的返回值return 400;//延時400毫秒關(guān)閉下拉刷新,由于我們使用的是補間動畫,平移動畫結(jié)束的時候還會回到最初的位置,為了不讓用戶看到,我們設(shè)置平移動畫的時長比刷新界面關(guān)閉的時長多100毫秒,這樣用戶就看不到這個變化,優(yōu)化用戶體驗(京東到家就有此問題,不得不吐槽一下,大廠也不長點心啊)

代碼如下:

/**
 * @Author:淘跑
 * @Date: 2018/4/1 09:35
 * @Use: SmartRefreshLayout 的自定義下拉刷新 Header
 * @
 * @-------------------修改記錄-------------------@
 * @
 * @Modifier: 修改者  v1
 * @Data: 修改時間
 * @Version: 修改次數(shù)
 * @EditContent: 修改內(nèi)容
 */

public class MyRefreshHeader extends LinearLayout implements RefreshHeader {
    private ImageView mImage;
    private AnimationDrawable refreshingAnim;
    private float mCurTranslationX;
    public MyRefreshHeader(Context context) {
        this(context, null, 0);
    }

    public MyRefreshHeader(Context context, @Nullable AttributeSet attrs) {
        this(context, attrs, 0);
    }

    public MyRefreshHeader(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        View view = View.inflate(context, R.layout.widget_my_refresh_header, this);
        mImage = (ImageView) view.findViewById(R.id.iv_refresh_header);
    }

    @NonNull
    @Override
    public View getView() {
        return this;
    }

    @Override
    public SpinnerStyle getSpinnerStyle() {
        return SpinnerStyle.Translate;
    }

    @Override
    public void onStartAnimator(RefreshLayout layout, int height, int extendHeight) {

    }

    /**
     * 狀態(tài)改變時調(diào)用。
     * @param refreshLayout
     * @param oldState
     * @param newState
     */
    @Override
    public void onStateChanged(RefreshLayout refreshLayout, RefreshState oldState, RefreshState newState) {
        switch (newState) {
            case PullDownToRefresh: //下拉刷新開始蔼水。正在下拉還沒松手時調(diào)用
                //每次重新下拉時震糖,將圖片資源重置為小車
                mImage.setImageResource(R.drawable.pull_to_refresh_people_0);
                break;
            case Refreshing: //正在刷新。只調(diào)用一次
                //狀態(tài)切換為正在刷新狀態(tài)時徙缴,設(shè)置圖片資源為小車的動畫并開始執(zhí)行
                mImage.setImageResource(R.drawable.anim_mypull_refreshing);
                refreshingAnim = (AnimationDrawable) mImage.getDrawable();
                refreshingAnim.start();
                break;
            case RefreshFinish://刷新結(jié)束
                //刷新結(jié)束時調(diào)用該動畫
                mCurTranslationX = mImage.getTranslationX();
                Animation translateAnimation = new TranslateAnimation(mCurTranslationX,1000,0,0);
                translateAnimation.setDuration(500);
                mImage.startAnimation(translateAnimation);
                break;
        }
    }

    /**
     * 動畫結(jié)束后調(diào)用
     */
    @Override
    public int onFinish(RefreshLayout layout, boolean success) {
        // 結(jié)束動畫
        if (refreshingAnim != null && refreshingAnim.isRunning()) {
            refreshingAnim.stop();
        }
        return 400;//延時400毫秒關(guān)閉下拉刷新
    }


    @Override
    public void setPrimaryColors(int... colors) {

    }

    @Override
    public void onInitialized(RefreshKernel kernel, int height, int extendHeight) {

    }

    /**
     * 下拉過程中不斷調(diào)用此方法试伙。從小變大的小車
     */

    @Override
    public void onMoving(boolean isDragging, float percent, int offset, int height, int maxDragHeight) {
        // 下拉的百分比小于100%時,不斷調(diào)用 setScale 方法改變圖片大小
        if (percent < 1) {
            mImage.setScaleX(percent);
            mImage.setScaleY(percent);
        }
    }

    @Override
    public void onReleased(@NonNull RefreshLayout refreshLayout, int height, int maxDragHeight) {

    }

    @Override
    public void onHorizontalDrag(float percentX, int offsetX, int offsetMax) {

    }

    @Override
    public boolean isSupportHorizontalDrag() {
        return false;
    }


}

貼出資源布局文件:

activity_jdrefresh

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout 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:fitsSystemWindows="true"
    android:layout_height="match_parent"
    tools:context="com.taopao.rxjavaretrofitcutmvp.ui.activity.customview.refresh.JDRefreshActivity">
    >
    <com.scwang.smartrefresh.layout.SmartRefreshLayout
        android:id="@+id/smart_mian"
        android:layout_width="match_parent"
        android:layout_height="match_parent">

        <com.taopao.rxjavaretrofitcutmvp.widget.refresh.MyRefreshHeader
            android:layout_width="match_parent"
            android:layout_height="wrap_content"></com.taopao.rxjavaretrofitcutmvp.widget.refresh.MyRefreshHeader>

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

            <TextView
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:text="先帝創(chuàng)業(yè)未半而中道崩殂于样,今天下三分疏叨,益州疲弊,此誠危急存亡之秋也穿剖。然侍衛(wèi)之臣不懈于內(nèi)蚤蔓,忠志之士忘身于外者,蓋追先帝之殊遇糊余,欲報之于陛下也秀又。誠宜開張圣聽,以光先帝遺德贬芥,恢弘志士之氣吐辙,不宜妄自菲薄,引喻失義蘸劈,以塞忠諫之路也昏苏。
宮中府中,俱為一體,陟罰臧否贤惯,不宜異同洼专。若有作奸犯科及為忠善者,宜付有司論其刑賞孵构,以昭陛下平明之理屁商,不宜偏私,使內(nèi)外異法也颈墅。
侍中蜡镶、侍郎郭攸之、費祎精盅、董允等帽哑,此皆良實,志慮忠純叹俏,是以先帝簡拔以遺陛下妻枕。愚以為宮中之事,事無大小粘驰,悉以咨之屡谐,然后施行,必能裨補闕漏蝌数,有所廣益愕掏。"
                android:textSize="30dp" />
        </ScrollView>
    </com.scwang.smartrefresh.layout.SmartRefreshLayout>
</LinearLayout>

widget_my_refresh_header

<?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"
    android:background="@color/white"
    android:padding="5dp">

    <ImageView
        android:layout_marginLeft="10dp"
        android:id="@+id/iv_refresh_header"
        android:layout_width="90dp"
        android:layout_height="80dp"
        android:scaleX="0"
        android:scaleY="0"
        android:translationY="0dp" />
    <ImageView
        android:layout_centerInParent="true"
        android:src="@drawable/pull_to_refresh_text_jddj"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
         />
</RelativeLayout>

anim_mypull_refreshing

<?xml version="1.0" encoding="utf-8"?>
<animation-list android:oneshot="false"
    xmlns:android="http://schemas.android.com/apk/res/android">
    <item android:duration="50" android:drawable="@drawable/pull_to_refresh_people_0" />
    <item android:duration="50" android:drawable="@drawable/pull_to_refresh_people_1" />
    <item android:duration="50" android:drawable="@drawable/pull_to_refresh_people_2" />
    <item android:duration="50" android:drawable="@drawable/pull_to_refresh_people_3" />
    <item android:duration="50" android:drawable="@drawable/pull_to_refresh_people_4" />
    <item android:duration="50" android:drawable="@drawable/pull_to_refresh_people_5" />
</animation-list>

代碼中調(diào)用

 private Handler mHandler = new Handler() {
        @Override
        public void handleMessage(Message msg) {
            mSmartMian.finishRefresh();
        }
  };
  //主要代碼
  mSmartMian.setOnRefreshListener(new OnRefreshListener() {
            @Override
            public void onRefresh(@NonNull RefreshLayout refreshLayout) {
                //模擬加載過程,延時關(guān)閉刷新
                mHandler.sendEmptyMessageDelayed(10, 1300);
            }
   });

好啦,以上就是仿京東到家下拉刷新自定義動畫的實現(xiàn)過程顶伞。

項目地址:https://github.com/404NotFuond/RxJava-Retrofit-CutMvp

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末饵撑,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子唆貌,更是在濱河造成了極大的恐慌滑潘,老刑警劉巖,帶你破解...
    沈念sama閱讀 221,635評論 6 515
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件锨咙,死亡現(xiàn)場離奇詭異语卤,居然都是意外死亡,警方通過查閱死者的電腦和手機酪刀,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,543評論 3 399
  • 文/潘曉璐 我一進店門粹舵,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人骂倘,你說我怎么就攤上這事眼滤。” “怎么了历涝?”我有些...
    開封第一講書人閱讀 168,083評論 0 360
  • 文/不壞的土叔 我叫張陵柠偶,是天一觀的道長情妖。 經(jīng)常有香客問我睬关,道長诱担,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 59,640評論 1 296
  • 正文 為了忘掉前任电爹,我火速辦了婚禮蔫仙,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘丐箩。我一直安慰自己摇邦,他們只是感情好,可當我...
    茶點故事閱讀 68,640評論 6 397
  • 文/花漫 我一把揭開白布屎勘。 她就那樣靜靜地躺著施籍,像睡著了一般。 火紅的嫁衣襯著肌膚如雪概漱。 梳的紋絲不亂的頭發(fā)上丑慎,一...
    開封第一講書人閱讀 52,262評論 1 308
  • 那天,我揣著相機與錄音瓤摧,去河邊找鬼竿裂。 笑死,一個胖子當著我的面吹牛照弥,可吹牛的內(nèi)容都是我干的腻异。 我是一名探鬼主播,決...
    沈念sama閱讀 40,833評論 3 421
  • 文/蒼蘭香墨 我猛地睜開眼这揣,長吁一口氣:“原來是場噩夢啊……” “哼悔常!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起给赞,我...
    開封第一講書人閱讀 39,736評論 0 276
  • 序言:老撾萬榮一對情侶失蹤机打,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后塞俱,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體姐帚,經(jīng)...
    沈念sama閱讀 46,280評論 1 319
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 38,369評論 3 340
  • 正文 我和宋清朗相戀三年障涯,在試婚紗的時候發(fā)現(xiàn)自己被綠了罐旗。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 40,503評論 1 352
  • 序言:一個原本活蹦亂跳的男人離奇死亡唯蝶,死狀恐怖九秀,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情粘我,我是刑警寧澤鼓蜒,帶...
    沈念sama閱讀 36,185評論 5 350
  • 正文 年R本政府宣布痹换,位于F島的核電站,受9級特大地震影響都弹,放射性物質(zhì)發(fā)生泄漏娇豫。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 41,870評論 3 333
  • 文/蒙蒙 一畅厢、第九天 我趴在偏房一處隱蔽的房頂上張望冯痢。 院中可真熱鬧,春花似錦框杜、人聲如沸浦楣。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,340評論 0 24
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽振劳。三九已至,卻和暖如春油狂,著一層夾襖步出監(jiān)牢的瞬間历恐,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,460評論 1 272
  • 我被黑心中介騙來泰國打工选调, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留夹供,地道東北人。 一個月前我還...
    沈念sama閱讀 48,909評論 3 376
  • 正文 我出身青樓仁堪,卻偏偏與公主長得像哮洽,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子弦聂,可洞房花燭夜當晚...
    茶點故事閱讀 45,512評論 2 359

推薦閱讀更多精彩內(nèi)容