首页 > 系统 > Android > 正文

Android仿京东、天猫下拉刷新效果

2019-12-12 03:25:57
字体:
来源:转载
供稿:网友

说到下拉刷新,相信大家都不陌生,现在基本上每个项目都会用到。我们公司的项目一直都是使用SwipeRefreshLayout,官方的Material Design风格,好用少Bug。现在下拉刷新大概有下面几种实现方式:一种是直接包在ListView或者RecyclerView的头部,有的则是像SwipeRefreshLayout一样,包在视图的最外层,个人建议使用包在最外层的做法,可拓展性比较强。下面用包在最外层的方法实现京东和天猫的下拉刷新。

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

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

大家有兴趣的可以去看一下这个下拉刷新框架,可拓展性非常强,兼容各种View的下拉刷新事件。

2.京东下拉刷新

先看看京东的下拉刷新动画:

从上图可以看出,就是一个动画,当然截图有点卡,首先,我们解压手机京东的app,得到上面的图片:

先看看头部刷新的布局怎么实现:
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="让购物更便捷"    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> 

咱们再看看android-Ultra-Pull-To-Refresh这个框架:

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); } 

这是一个下拉刷新事件处理接口,包括准备刷新,开始刷新,刷新完成和刷新改变等事件的处理,直接上代码:
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;   /**   * 状态识别   */  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 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,开启跑步动画   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);   //停止动画   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设置     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("松开刷新...");     }     break;    case STATE_BEGIN:     mTvRemind.setText("更新中...");     break;    case STATE_FINISH:     mTvRemind.setText("加载完成...");     break;   }  } } 

创建一个成员变量mState,用于保存下拉刷新的时候,每一个状态,然后根据保存好的状态在UIPositionChange的接口中,对UI进行相应的修改,保存每个状态文本的提示,在下拉的过程中,通过UIPositionChange的回调,获取PtrIndicator中,可以获取下拉的百分比,根据这个百分比我们可以做很多东西,例如京东的快递小哥从远处跑过来拿商品,以及快递小哥与商品之间的大小,都可以根据这个PtrIndicator百分比进行设置其大小的比例,跑过来这个过程我使用的方法是利用marginRight进行设置两者之间的距离,当达到下拉刷新的临界点时,快递小哥跟商品之间的margin为0,达到了快递小哥获取商品的效果,然后当刷新的时候,隐藏商品,使用之前所提供的三张图片进行效应的切换,也就是动画:

<?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.天猫下拉刷新

天猫的更简单,毫无动画可言,说白了就是个GIF,大家可以去下载个apk,解压后能得到其gif。原理跟之前的是一样,但这里我使用的是fresco进行加载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;    /**   * 状态识别   */  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) {   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)     //设置uri,加载本地的gif资源     .setUri(Uri.parse("res://" + getContext().getPackageName() + "/" + R.drawable.tm_mui_bike))//设置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("松开立即刷新");     }     break;    case STATE_BEGIN:     mTvRemind.setText("正在刷新...");     break;    case STATE_FINISH:     mTvRemind.setText("加载完成...");     break;   }  } } 

效果图如下:

最后附上github地址:
https://github.com/shineflower/JdTmallPullToRefresh

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持武林网。

发表评论 共有条评论
用户名: 密码:
验证码: 匿名发表