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

说到下拉刷新,相信大家都不陌生,现在基本上每个项目都会用到。我们公司的项目一直都是使用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

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

(0)

相关推荐

  • Android中使用RecyclerView实现下拉刷新和上拉加载

    推荐阅读:使用RecyclerView添加Header和Footer的方法                       RecyclerView的使用之HelloWorld RecyclerView 是Android L版本中新添加的一个用来取代ListView的SDK,它的灵活性与可替代性比listview更好.本文给大家介绍如何为RecyclerView添加下拉刷新和上拉加载,过去在ListView当中添加下拉刷新和上拉加载是非常方便的利用addHeaderView和addFooterVie

  • android下拉刷新ListView的介绍和实现代码

    大致上,我们发现,下拉刷新的列表和一般列表的区别是,当滚动条在顶端的时候,再往下拉动就会把整个列表拉下来,显示出松开刷新的提示.由此可以看出,在构建这个下拉刷新的组件的时候,只用继承ListView,然后重写onTouchEvent就能实现.还有就是要能在xml布局文件中引用,还需要一个参数为Context,AttributeSet的构造函数. 表面上的功能大概就这些了.另一方面,刷新的行为似乎还没有定义,在刷新前做什么,刷新时要做什么,刷新完成后要做什么,这些行为写入一个接口中,然后让组件去实

  • Android PullToRefreshLayout下拉刷新控件的终结者

    说到下拉刷新控件,网上版本有很多,很多软件也都有下拉刷新功能.有一个叫XListView的,我看别人用过,没看过是咋实现的,看这名字估计是继承自ListView修改的,不过效果看起来挺丑的,也没什么扩展性,太单调了.看了QQ2014的列表下拉刷新,发现挺好看的,我喜欢,贴一下图看一下qq的下拉刷新效果: 不错吧?嗯,是的.一看就知道实现方式不一样.咱们今天就来实现一个下拉刷新控件.由于有时候不仅仅是ListView需要下拉刷新,ExpandableListView和GridView也有这个需求,

  • Android新浪微博下拉刷新(最新消息显示在最上面)

    查看最新消息要用到类似新浪微博下拉刷新 功能!把最新的消息显示在最上面! 代码如下: PullToRefreshListView类代码 复制代码 代码如下: package com.markupartist.android.widget; import java.util.Date; import com.markupartist.android.example.pulltorefresh.R; import android.content.Context; import android.uti

  • android开发教程之实现listview下拉刷新和上拉刷新效果

    复制代码 代码如下: public class PullToLoadListView extends ListView implements OnScrollListener { private static final String TAG = PullToLoadListView.class.getSimpleName(); private static final int STATE_NON = 0; private static final int STATE_PULL_TO_REFRE

  • Android下拉刷新完全解析,教你如何一分钟实现下拉刷新功能(附源码)

    最近项目中需要用到ListView下拉刷新的功能,一开始想图省事,在网上直接找一个现成的,可是尝试了网上多个版本的下拉刷新之后发现效果都不怎么理想.有些是因为功能不完整或有Bug,有些是因为使用起来太复杂,十全十美的还真没找到.因此我也是放弃了在网上找现成代码的想法,自己花功夫编写了一种非常简单的下拉刷新实现方案,现在拿出来和大家分享一下.相信在阅读完本篇文章之后,大家都可以在自己的项目中一分钟引入下拉刷新功能. 首先讲一下实现原理.这里我们将采取的方案是使用组合View的方式,先自定义一个布局

  • Android下拉刷新上拉加载控件(适用于所有View)

    前面写过一篇关于下拉刷新控件的文章下拉刷新控件终结者:PullToRefreshLayout,后来看到好多人还有上拉加载更多的需求,于是就在前面下拉刷新控件的基础上进行了改进,加了上拉加载的功能.不仅如此,我已经把它改成了对所有View都通用!可以随心所欲使用这两个功能~~ 我做了一个大集合的demo,实现了ListView.GridView.ExpandableListView.ScrollView.WebView.ImageView.TextView的下拉刷新和上拉加载.后面会提供demo的

  • Android RecyclerView实现下拉刷新和上拉加载

    RecyclerView已经出来很久了,许许多多的项目都开始从ListView转战RecyclerView,那么,上拉加载和下拉刷新是一件很有必要的事情. 在ListView上,我们可以通过自己添加addHeadView和addFootView去添加头布局和底部局实现自定义的上拉和下拉,或者使用一些第三方库来简单的集成,例如Android-pulltorefresh或者android-Ultra-Pull-to-Refresh,后者的自定义更强,但需要自己实现上拉加载. 而在下面我们将用两种方式

  • Android下拉刷新ListView——RTPullListView(demo)

    下拉刷新在越来越多的App中使用,已经形成一种默认的用户习惯,遇到列表显示的内容时,用户已经开始习惯性的拉拉.在交互习惯上已经形成定性.之前在我的文章<IOS学习笔记34-EGOTableViewPullRefresh实现下拉刷新>中介绍过如何在IOS上实现下拉刷新的功能.今天主要介绍下在Android上实现下拉刷新的Demo,下拉控件参考自Github上开源项目PullToRefresh,并做简单修改.最终效果如下:                         工程结构如下: 使用过程中

  • Android实现上拉加载更多以及下拉刷新功能(ListView)

    首先为大家介绍Andorid5.0原生下拉刷新简单实现. 先上效果图: 相对于上一个19.1.0版本中的横条效果好看了很多.使用起来也很简单. <FrameLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:id="@+id/container" and

随机推荐