博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
【Android从零撸美团二】仿美团下拉刷新自定义动画
阅读量:4122 次
发布时间:2019-05-25

本文共 5497 字,大约阅读时间需要 18 分钟。

这是【从零撸美团】系列文章第二篇。

项目地址:

今天写了下拉刷新,框架用的是 ,不为啥,因为

Github 上它有 9.5kstar,中文支持好节省时间。

先上图:

在这里插入图片描述

一、分析

美团的下拉加载动画初看挺简单的,就一个卖萌的小人。细看的话还稍微有点复杂,一共有三个状态。

  1. 刚开始下拉的时候,小脑袋从小变大的过程。
  2. 下拉到一定程度但还没松手,小人翻了个跟头直到完全出现。再往下拉保持最后完全出现的状态。
  3. 松开后左右摇头卖萌直至加载结束回弹回去。

这是三个动画啊!真佩服这些大厂,简单的加载动画都搞这么复杂。。

分析完过程该想怎么实现了。

二、反编译app看实现原理

最简单直白的方法就是反编译美团app,虽然看不到代码但资源文件能还原出来,图片和 xml 文件完美还原。

在这里插入图片描述

反编译工具是 ,使用方法官网上都有就不啰嗦了。

大部分图片都放在 res/drawable-xhdpi-v4res/drawable-xxhdpi-v4 两个文件夹内,仔细找下能看到多张连续的 loading 图片。这里给美团程序猿点个赞,文件命名都很规范,很好找~

在这里插入图片描述

在这里插入图片描述

看到图片后知道原来它用的是最普通的帧动画啊,也不是太复杂。

拿到资源图片,知道实现原理,就开工吧!

三、实现动画效果

首先自定义View CustomRefreshHeader 继承自 LinearLayout,并实现 SmartRefreshLayoutRefreshHeader 接口。

然后主要就是重写 RefreshHeader 接口中的方法,里面提供了下拉刷新时不同阶段的回调,找到对应的方法码代码就好。

public class CustomRefreshHeader extends LinearLayout implements RefreshHeader {    private ImageView mImage;    private AnimationDrawable pullDownAnim;    private AnimationDrawable refreshingAnim;    private boolean hasSetPullDownAnim = false;    public CustomRefreshHeader(Context context) {        this(context, null, 0);    }    public CustomRefreshHeader(Context context, @Nullable AttributeSet attrs) {        this(context, attrs, 0);    }    public CustomRefreshHeader(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {        super(context, attrs, defStyleAttr);        View view = View.inflate(context, R.layout.widget_custom_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) {    }    /**     * 状态改变时调用。在这里切换第三阶段的动画卖萌小人     * @param refreshLayout     * @param oldState     * @param newState     */    @Override    public void onStateChanged(RefreshLayout refreshLayout, RefreshState oldState, RefreshState newState) {        switch (newState) {            case PullDownToRefresh: //下拉刷新开始。正在下拉还没松手时调用                //每次重新下拉时,将图片资源重置为小人的大脑袋                mImage.setImageResource(R.drawable.commonui_pull_image);                break;            case Refreshing: //正在刷新。只调用一次                //状态切换为正在刷新状态时,设置图片资源为小人卖萌的动画并开始执行                mImage.setImageResource(R.drawable.anim_pull_refreshing);                refreshingAnim = (AnimationDrawable) mImage.getDrawable();                refreshingAnim.start();                break;            case ReleaseToRefresh:                break;        }    }    /**     * 下拉过程中不断调用此方法。第一阶段从小变大的小人头动画,和第二阶段翻跟头动画都在这里设置     */    @Override    public void onPullingDown(float percent, int offset, int headerHeight, int extendHeight) {        Logger.d("percent: " + percent);        // 下拉的百分比小于100%时,不断调用 setScale 方法改变图片大小        if (percent < 1) {            mImage.setScaleX(percent);            mImage.setScaleY(percent);            //是否执行过翻跟头动画的标记            if (hasSetPullDownAnim) {                hasSetPullDownAnim = false;            }        }        //当下拉的高度达到Header高度100%时,开始加载正在下拉的初始动画,即翻跟头        if (percent >= 1.0) {            //因为这个方法是不停调用的,防止重复            if (!hasSetPullDownAnim) {                mImage.setImageResource(R.drawable.anim_pull_end);                pullDownAnim = (AnimationDrawable) mImage.getDrawable();                pullDownAnim.start();                hasSetPullDownAnim = true;            }        }    }    /**     * 动画结束后调用     */    @Override    public int onFinish(RefreshLayout layout, boolean success) {        // 结束动画        if (pullDownAnim != null && pullDownAnim.isRunning()) {            pullDownAnim.stop();        }        if (refreshingAnim != null && refreshingAnim.isRunning()) {            refreshingAnim.stop();        }        //重置状态        hasSetPullDownAnim = false;        return 0;    }    @Override    public void onReleasing(float percent, int offset, int headerHeight, int extendHeight) {    }    @Override    public void onRefreshReleased(RefreshLayout layout, int headerHeight, int extendHeight) {    }    @Override    public void setPrimaryColors(int... colors) {    }    @Override    public void onInitialized(RefreshKernel kernel, int height, int extendHeight) {    }    @Override    public void onHorizontalDrag(float percentX, int offsetX, int offsetMax) {    }    @Override    public boolean isSupportHorizontalDrag() {        return false;    }}

逻辑主要在 onStateChanged()onPullingDown() 方法里,代码中注释写的很详细。

切换状态原理是每次都给 ImageView 设置对应的资源图片或动画文件,然后得到 AnimationDrawable 开启动画,如下:

mImage.setImageResource(R.drawable.anim_pull_end);pullDownAnim = (AnimationDrawable) mImage.getDrawable();pullDownAnim.start();

代码中调用:

smartRefreshLayout.setRefreshHeader(new CustomRefreshHeader(getActivity()));        smartRefreshLayout.setOnRefreshLoadmoreListener(new OnRefreshLoadmoreListener() {            @Override            public void onLoadmore(RefreshLayout refreshlayout) {                Logger.d("onLoadmore");                smartRefreshLayout.finishLoadmore(2000, true);            }            @Override            public void onRefresh(RefreshLayout refreshlayout) {                Logger.d("onRefresh");                smartRefreshLayout.finishRefresh(2000, true);            }        });

贴出资源布局文件:

widget_custom_refresh_header.xml

anim_pull_end.xml

anim_pull_refreshing.xml

好啦,以上就是仿美团下拉刷新自定义动画的实现过程。

源码地址:

【从零撸美团】专题地址:

转载地址:http://lvvpi.baihongyu.com/

你可能感兴趣的文章
JS 网页中一个控件变化,其他的都不可读
查看>>
JSP 页面中对Cookie的操作
查看>>
Ajax (部分二:prototype.js代码后半部分)自己做的,总结页面向后台传Form值、单个值和后台向前台传一个或是一组值...
查看>>
Ajax (部分二:prototype.js代码前半部)自己做的,总结页面向后台传Form值、单个值和后台向前台传一个或是一组值...
查看>>
Ajax (部分一)自己做的,总结页面向后台传Form值、单个值和后台向前台传一个或是一组值...
查看>>
JS 横向图片跑马灯效果
查看>>
JS 屏蔽按键效果和改变按键效果
查看>>
JS 屏蔽右键菜单
查看>>
Java 的上溯造型和下溯造型以及举例,以及判断参数等指向的类
查看>>
Java 轻量级锁原理详解(Lightweight Locking)
查看>>
Java 运算符总计
查看>>
JSP 页面缓存以及清除缓存
查看>>
Java多线程的相关机制
查看>>
Java线程知识深入解析(1)
查看>>
Java线程知识深入解析(2)
查看>>
RUP软件开发设计模式
查看>>
十条不错的编程观点
查看>>
惹恼程序员的十件事
查看>>
Java 线程编程中的同步、重复、定时
查看>>
数据库 SQLServer2005 中将一个表中从未重复的项筛选出来、去除重复项,只要一条...
查看>>