Android仿京東、天貓下拉刷新效果
說(shuō)到下拉刷新,相信大家都不陌生,現(xiàn)在基本上每個(gè)項(xiàng)目都會(huì)用到。我們公司的項(xiàng)目一直都是使用SwipeRefreshLayout,官方的Material Design風(fēng)格,好用少Bug?,F(xiàn)在下拉刷新大概有下面幾種實(shí)現(xiàn)方式:一種是直接包在ListView或者RecyclerView的頭部,有的則是像SwipeRefreshLayout一樣,包在視圖的最外層,個(gè)人建議使用包在最外層的做法,可拓展性比較強(qiáng)。下面用包在最外層的方法實(shí)現(xiàn)京東和天貓的下拉刷新。
1.使用框架Android-Ultra-Pull-To-Refresh
https://github.com/liaohuqiu/android-Ultra-Pull-To-Refresh
大家有興趣的可以去看一下這個(gè)下拉刷新框架,可拓展性非常強(qiáng),兼容各種View的下拉刷新事件。
2.京東下拉刷新
先看看京東的下拉刷新動(dòng)畫:

從上圖可以看出,就是一個(gè)動(dòng)畫,當(dāng)然截圖有點(diǎn)卡,首先,我們解壓手機(jī)京東的app,得到上面的圖片:

先看看頭部刷新的布局怎么實(shí)現(xiàn):
jd_refresh_header_view.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="@drawable/a2a" /> <ImageView android:id="@+id/iv_goods" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_gravity="right|center" android:src="@drawable/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="讓購(gòu)物更便捷" 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="松開(kāi)刷新" android:textSize="12sp" /> </LinearLayout> </RelativeLayout>
咱們?cè)倏纯碼ndroid-Ultra-Pull-To-Refresh這個(gè)框架:
package in.srain.cube.views.ptr;
import in.srain.cube.views.ptr.indicator.PtrIndicator;
/**
*
*/
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);
}
這是一個(gè)下拉刷新事件處理接口,包括準(zhǔn)備刷新,開(kāi)始刷新,刷新完成和刷新改變等事件的處理,直接上代碼:
JdRefreshHeader.java
package com.jackie.pulltorefresh.jd;
import android.content.Context;
import android.graphics.drawable.AnimationDrawable;
import android.util.AttributeSet;
import android.view.LayoutInflater;
import android.view.View;
import android.widget.FrameLayout;
import android.widget.ImageView;
import android.widget.TextView;
import com.jackie.pulltorefresh.R;
import in.srain.cube.views.ptr.PtrFrameLayout;
import in.srain.cube.views.ptr.PtrUIHandler;
import in.srain.cube.views.ptr.indicator.PtrIndicator;
/**
* 下拉刷新HeaderView
*/
public class JdRefreshHeader extends FrameLayout implements PtrUIHandler {
/**
* 提醒文本
*/
private TextView mTvRemind;
/**
* 快遞員logo
*/
private ImageView mIvMan;
/**
* 商品logo
*/
private ImageView mIvGoods;
/**
* 狀態(tài)識(shí)別
*/
private int mState;
/**
* 重置
* 準(zhǔn)備刷新
* 開(kāi)始刷新
* 結(jié)束刷新
*/
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;
/**
* 動(dòng)畫
*/
private AnimationDrawable mAnimationDrawable;
public JdRefreshHeader(Context context) {
this(context, null);
}
public JdRefreshHeader(Context context, AttributeSet attrs) {
this(context, attrs, 0);
}
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,開(kāi)啟跑步動(dòng)畫
mIvGoods.setVisibility(View.GONE);
mIvMan.setBackgroundResource(R.drawable.runningman);
mAnimationDrawable = (AnimationDrawable) mIvMan.getBackground();
if (!mAnimationDrawable.isRunning()) {
mAnimationDrawable.start();
}
}
@Override
public void onUIRefreshComplete(PtrFrameLayout frame) {
mState = STATE_FINISH;
mIvGoods.setVisibility(View.VISIBLE);
//停止動(dòng)畫
if (mAnimationDrawable.isRunning()) {
mAnimationDrawable.stop();
}
mIvMan.setBackgroundResource(R.drawable.a2a);
}
@Override
public void onUIPositionChange(PtrFrameLayout frame, boolean isUnderTouch, byte status, PtrIndicator ptrIndicator) {
//處理提醒字體
switch (mState) {
case STATE_PREPARE:
//logo設(shè)置
mIvMan.setAlpha(ptrIndicator.getCurrentPercent());
mIvGoods.setAlpha(ptrIndicator.getCurrentPercent());
LayoutParams params = (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());
params.setMargins(0, 0, marginRight, 0);
mIvMan.setLayoutParams(params);
}
if (ptrIndicator.getCurrentPercent() < 1.2) {
mTvRemind.setText("下拉刷新...");
} else {
mTvRemind.setText("松開(kāi)刷新...");
}
break;
case STATE_BEGIN:
mTvRemind.setText("更新中...");
break;
case STATE_FINISH:
mTvRemind.setText("加載完成...");
break;
}
}
}
創(chuàng)建一個(gè)成員變量mState,用于保存下拉刷新的時(shí)候,每一個(gè)狀態(tài),然后根據(jù)保存好的狀態(tài)在UIPositionChange的接口中,對(duì)UI進(jìn)行相應(yīng)的修改,保存每個(gè)狀態(tài)文本的提示,在下拉的過(guò)程中,通過(guò)UIPositionChange的回調(diào),獲取PtrIndicator中,可以獲取下拉的百分比,根據(jù)這個(gè)百分比我們可以做很多東西,例如京東的快遞小哥從遠(yuǎn)處跑過(guò)來(lái)拿商品,以及快遞小哥與商品之間的大小,都可以根據(jù)這個(gè)PtrIndicator百分比進(jìn)行設(shè)置其大小的比例,跑過(guò)來(lái)這個(gè)過(guò)程我使用的方法是利用marginRight進(jìn)行設(shè)置兩者之間的距離,當(dāng)達(dá)到下拉刷新的臨界點(diǎn)時(shí),快遞小哥跟商品之間的margin為0,達(dá)到了快遞小哥獲取商品的效果,然后當(dāng)刷新的時(shí)候,隱藏商品,使用之前所提供的三張圖片進(jìn)行效應(yīng)的切換,也就是動(dòng)畫:
<?xml version="1.0" encoding="utf-8"?> <animation-list xmlns:android="http://schemas.android.com/apk/res/android" android:oneshot="false"> <item android:drawable="@drawable/a2b" android:duration="70" /> <item android:drawable="@drawable/a2c" android:duration="70" /> <item android:drawable="@drawable/a2d" android:duration="70" /> </animation-list>
效果圖如下:

3.天貓下拉刷新
天貓的更簡(jiǎn)單,毫無(wú)動(dòng)畫可言,說(shuō)白了就是個(gè)GIF,大家可以去下載個(gè)apk,解壓后能得到其gif。原理跟之前的是一樣,但這里我使用的是fresco進(jìn)行加載gif,方法有很多,大家感興趣的可以去試試。

TmallRefreshHeader.java
package com.jackie.pulltorefresh.tmall;
import android.content.Context;
import android.net.Uri;
import android.util.AttributeSet;
import android.view.LayoutInflater;
import android.view.View;
import android.widget.FrameLayout;
import android.widget.TextView;
import com.facebook.drawee.backends.pipeline.Fresco;
import com.facebook.drawee.interfaces.DraweeController;
import com.facebook.drawee.view.SimpleDraweeView;
import com.jackie.pulltorefresh.R;
import in.srain.cube.views.ptr.PtrFrameLayout;
import in.srain.cube.views.ptr.PtrUIHandler;
import in.srain.cube.views.ptr.indicator.PtrIndicator;
/**
* 下拉刷新HeaderView
*/
public class TmallRefreshHeader extends FrameLayout implements PtrUIHandler {
/**
* 提醒文本
*/
private TextView mTvRemind;
/**
* 狀態(tài)識(shí)別
*/
private int mState;
/**
* 重置
* 準(zhǔn)備刷新
* 開(kāi)始刷新
* 結(jié)束刷新
*/
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) {
this(context, null);
}
public TmallRefreshHeader(Context context, AttributeSet attrs) {
this(context, attrs, 0);
}
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 draweeController = Fresco.newDraweeControllerBuilder()
.setAutoPlayAnimations(true)
//設(shè)置uri,加載本地的gif資源
.setUri(Uri.parse("res://" + getContext().getPackageName() + "/" + R.drawable.tm_mui_bike))//設(shè)置uri
.build();
sdv.setController(draweeController);
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("松開(kāi)立即刷新");
}
break;
case STATE_BEGIN:
mTvRemind.setText("正在刷新...");
break;
case STATE_FINISH:
mTvRemind.setText("加載完成...");
break;
}
}
}
效果圖如下:

最后附上github地址:
https://github.com/shineflower/JdTmallPullToRefresh
以上就是本文的全部?jī)?nèi)容,希望對(duì)大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。
- Android 仿京東秒殺倒計(jì)時(shí)代碼
- Android 仿淘寶、京東商品詳情頁(yè)向上拖動(dòng)查看圖文詳情控件DEMO詳解
- Android中使用TextView實(shí)現(xiàn)高仿京東淘寶各種倒計(jì)時(shí)效果
- Android 仿京東、拼多多商品分類頁(yè)的示例代碼
- Android高仿京東垂直循環(huán)滾動(dòng)新聞欄
- Android 仿京東側(cè)滑篩選實(shí)例代碼
- Android仿支付寶、京東的密碼鍵盤和輸入框
- Android仿京東、天貓商品詳情頁(yè)
- android仿京東商品屬性篩選功能
- Android實(shí)現(xiàn)京東秒殺界面
相關(guān)文章
Android開(kāi)發(fā)服務(wù)Service全面講解
Android的服務(wù)是開(kāi)發(fā)Android應(yīng)用程序的重要組成部分。不同于活動(dòng)Activity,服務(wù)是在后臺(tái)運(yùn)行,服務(wù)沒(méi)有接口,生命周期也與活動(dòng)Activity非常不同。通過(guò)使用服務(wù)我們可以實(shí)現(xiàn)一些后臺(tái)操作,比如想從遠(yuǎn)程服務(wù)器加載一個(gè)網(wǎng)頁(yè)等,下面來(lái)看看詳細(xì)內(nèi)容,需要的朋友可以參考下2023-02-02
Android圖片處理:識(shí)別圖像方向并顯示實(shí)例教程
在Android中使用ImageView顯示圖片的時(shí)候發(fā)現(xiàn)圖片顯示不正,方向偏了或者倒過(guò)來(lái)了,下面與大家分享下具體的解決方法,感性的朋友可以參考下2013-06-06
Android自定義View實(shí)現(xiàn)抽獎(jiǎng)轉(zhuǎn)盤
這篇文章主要為大家詳細(xì)介紹了Android自定義View實(shí)現(xiàn)抽獎(jiǎng)轉(zhuǎn)盤,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2018-12-12
Android Studio實(shí)現(xiàn)格式化XML代碼順序
這篇文章主要介紹了Android Studio實(shí)現(xiàn)格式化XML代碼順序,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧2020-03-03
Android setButtonDrawable()的兼容問(wèn)題解決辦法
這篇文章主要介紹了Android setButtonDrawable()的兼容問(wèn)題解決辦法的相關(guān)資料,需要的朋友可以參考下2017-03-03
Android開(kāi)發(fā)中應(yīng)用程序分享功能實(shí)例
這篇文章主要介紹了Android開(kāi)發(fā)中應(yīng)用程序分享功能,結(jié)合實(shí)例形式分析了基于Intent實(shí)現(xiàn)Android程序分享功能的技巧,需要的朋友可以參考下2016-02-02
Android實(shí)現(xiàn)登錄注冊(cè)頁(yè)面(下)
這篇文章主要介紹了Android實(shí)現(xiàn)登錄注冊(cè)頁(yè)面的第二篇,實(shí)現(xiàn)驗(yàn)證登錄和記住密碼功能,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2022-04-04

