項目地址: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) SmartRefreshLayout
的 RefreshHeader
接口演训。
然后主要就是重寫 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)過程顶伞。