本篇博客代码下载地址:https://github.com/Yalantis/Taurus

最近在github上看到了好多高端、大气、上档次的动画效果,如果给你的项目中加上这些动画,相信你的app一定很优秀,今天给大家分析一下来自Yalantis的一个超好看的下拉刷新动画。

首先我们看一下效果如何:

怎么样?是不是很高大上?接下来我们看一下代码:

一、首先我们需要自定义刷新的动态RefreshView(也就是下拉时候的头)

1.初始化头所占用的Dimens

private void initiateDimens() {mScreenWidth = mContext.getResources().getDisplayMetrics().widthPixels;mJetTopOffset = mParent.getTotalDragDistance() * 0.5f;mTop = -mParent.getTotalDragDistance();}

2.为头填充图片,设置图片的大小

分别为左边的云彩,右边的云彩,中间的云彩还有中间的飞机,飞机是带有动画的,下面会介绍飞机的动画
private void createBitmaps() {mLeftClouds = BitmapFactory.decodeResource(mContext.getResources(), R.drawable.clouds_left);mRightClouds = BitmapFactory.decodeResource(mContext.getResources(), R.drawable.clouds_right);mFrontClouds = BitmapFactory.decodeResource(mContext.getResources(), R.drawable.clouds_center);mJet = BitmapFactory.decodeResource(mContext.getResources(), R.drawable.airplane);mJetWidthCenter = mJet.getWidth() / 2;mJetHeightCenter = mJet.getHeight() / 2;mFrontCloudWidthCenter = mFrontClouds.getWidth() / 2;mFrontCloudHeightCenter = mFrontClouds.getHeight() / 2;mRightCloudsWidthCenter = mRightClouds.getWidth() / 2;mRightCloudsHeightCenter = mRightClouds.getHeight() / 2;mLeftCloudsWidthCenter = mLeftClouds.getWidth() / 2;mLeftCloudsHeightCenter = mLeftClouds.getHeight() / 2;}

3.然后我们来画这个头

public void draw(@NonNull Canvas canvas) {final int saveCount = canvas.save();// DRAW BACKGROUND.canvas.drawColor(mContext.getResources().getColor(R.color.sky_background));if (isRefreshing) {// Set up new set of windwhile (mWinds.size() < WIND_SET_AMOUNT) {float y = (float) (mParent.getTotalDragDistance() / (Math.random() * RANDOM_Y_COEFFICIENT));float x = random(MIN_WIND_X_OFFSET, MAX_WIND_X_OFFSET);// Magic with checking interval between windsif (mWinds.size() > 1) {y = 0;while (y == 0) {float tmp = (float) (mParent.getTotalDragDistance() / (Math.random() * RANDOM_Y_COEFFICIENT));for (Map.Entry<Float, Float> wind : mWinds.entrySet()) {// We want that interval will be greater than fifth part of draggable distanceif (Math.abs(wind.getKey() - tmp) > mParent.getTotalDragDistance() / RANDOM_Y_COEFFICIENT) {y = tmp;} else {y = 0;break;}}}}mWinds.put(y, x);drawWind(canvas, y, x);}// Draw current set of windif (mWinds.size() >= WIND_SET_AMOUNT) {for (Map.Entry<Float, Float> wind : mWinds.entrySet()) {drawWind(canvas, wind.getKey(), wind.getValue());}}// We should to create new set of windsif (mInverseDirection && mNewWindSet) {mWinds.clear();mNewWindSet = false;mWindLineWidth = random(MIN_WIND_LINE_WIDTH, MAX_WIND_LINE_WIDTH);}// needed for checking directionmLastAnimationTime = mLoadingAnimationTime;}drawJet(canvas);drawSideClouds(canvas);drawCenterClouds(canvas);canvas.restoreToCount(saveCount);}
/*** Draw wind on loading animation** @param canvas  - area where we will draw* @param y       - y position fot one of lines* @param xOffset - x offset for on of lines*/private void drawWind(Canvas canvas, float y, float xOffset) {/* We should multiply current animation time with this coefficient for taking all screen width in timeRemoving slowing of animation with dividing on {@LINK #SLOW_DOWN_ANIMATION_COEFFICIENT}And we should don't forget about distance that should "fly" line that depend on screen of device and x offset*/float cof = (mScreenWidth + xOffset) / (LOADING_ANIMATION_COEFFICIENT / SLOW_DOWN_ANIMATION_COEFFICIENT);float time = mLoadingAnimationTime;// HORRIBLE HACK FOR REVERS ANIMATION THAT SHOULD WORK LIKE RESTART ANIMATIONif (mLastAnimationTime - mLoadingAnimationTime > 0) {mInverseDirection = true;// take time from 0 to end of animation timetime = (LOADING_ANIMATION_COEFFICIENT / SLOW_DOWN_ANIMATION_COEFFICIENT) - mLoadingAnimationTime;} else {mNewWindSet = true;mInverseDirection = false;}// Taking current x position of drawing wind// For fully disappearing of line we should subtract wind line widthfloat x = (mScreenWidth - (time * cof)) + xOffset - mWindLineWidth;float xEnd = x + mWindLineWidth;canvas.drawLine(x, y, xEnd, y, mWindPaint);}private void drawSideClouds(Canvas canvas) {Matrix matrixLeftClouds = mMatrix;Matrix matrixRightClouds = mAdditionalMatrix;matrixLeftClouds.reset();matrixRightClouds.reset();// Drag percent will newer get more then 1 herefloat dragPercent = Math.min(1f, Math.abs(mPercent));boolean overdrag = false;// But we check here for overdragif (mPercent > 1.0f) {overdrag = true;}float scale;float scalePercentDelta = dragPercent - SCALE_START_PERCENT;if (scalePercentDelta > 0) {float scalePercent = scalePercentDelta / (1.0f - SCALE_START_PERCENT);scale = SIDE_CLOUDS_INITIAL_SCALE + (SIDE_CLOUDS_FINAL_SCALE - SIDE_CLOUDS_INITIAL_SCALE) * scalePercent;} else {scale = SIDE_CLOUDS_INITIAL_SCALE;}// Current y position of cloudsfloat dragYOffset = mParent.getTotalDragDistance() * (1.0f - dragPercent);// Position where clouds fully visible on screen and we should drag them with content of listViewint cloudsVisiblePosition = mParent.getTotalDragDistance() / 2 - mLeftCloudsHeightCenter;boolean needMoveCloudsWithContent = false;if (dragYOffset < cloudsVisiblePosition) {needMoveCloudsWithContent = true;}float offsetRightX = mScreenWidth - mRightClouds.getWidth();float offsetRightY = (needMoveCloudsWithContent? mParent.getTotalDragDistance() * dragPercent - mLeftClouds.getHeight(): dragYOffset)+ (overdrag ? mTop : 0);float offsetLeftX = 0;float offsetLeftY = (needMoveCloudsWithContent? mParent.getTotalDragDistance() * dragPercent - mLeftClouds.getHeight(): dragYOffset)+ (overdrag ? mTop : 0);// Magic with animation on loading processif (isRefreshing) {if (checkCurrentAnimationPart(AnimationPart.FIRST)) {offsetLeftY += getAnimationPartValue(AnimationPart.FIRST) / Y_SIDE_CLOUDS_SLOW_DOWN_COF;offsetRightX -= getAnimationPartValue(AnimationPart.FIRST) / X_SIDE_CLOUDS_SLOW_DOWN_COF;} else if (checkCurrentAnimationPart(AnimationPart.SECOND)) {offsetLeftY += getAnimationPartValue(AnimationPart.SECOND) / Y_SIDE_CLOUDS_SLOW_DOWN_COF;offsetRightX -= getAnimationPartValue(AnimationPart.SECOND) / X_SIDE_CLOUDS_SLOW_DOWN_COF;} else if (checkCurrentAnimationPart(AnimationPart.THIRD)) {offsetLeftY -= getAnimationPartValue(AnimationPart.THIRD) / Y_SIDE_CLOUDS_SLOW_DOWN_COF;offsetRightX += getAnimationPartValue(AnimationPart.THIRD) / X_SIDE_CLOUDS_SLOW_DOWN_COF;} else if (checkCurrentAnimationPart(AnimationPart.FOURTH)) {offsetLeftY -= getAnimationPartValue(AnimationPart.FOURTH) / X_SIDE_CLOUDS_SLOW_DOWN_COF;offsetRightX += getAnimationPartValue(AnimationPart.FOURTH) / Y_SIDE_CLOUDS_SLOW_DOWN_COF;}}matrixRightClouds.postScale(scale, scale, mRightCloudsWidthCenter, mRightCloudsHeightCenter);matrixRightClouds.postTranslate(offsetRightX, offsetRightY);matrixLeftClouds.postScale(scale, scale, mLeftCloudsWidthCenter, mLeftCloudsHeightCenter);matrixLeftClouds.postTranslate(offsetLeftX, offsetLeftY);canvas.drawBitmap(mLeftClouds, matrixLeftClouds, null);canvas.drawBitmap(mRightClouds, matrixRightClouds, null);}private void drawCenterClouds(Canvas canvas) {Matrix matrix = mMatrix;matrix.reset();float dragPercent = Math.min(1f, Math.abs(mPercent));float scale;float overdragPercent = 0;boolean overdrag = false;if (mPercent > 1.0f) {overdrag = true;// Here we want know about how mach percent of over drag we doneoverdragPercent = Math.abs(1.0f - mPercent);}float scalePercentDelta = dragPercent - SCALE_START_PERCENT;if (scalePercentDelta > 0) {float scalePercent = scalePercentDelta / (1.0f - SCALE_START_PERCENT);scale = CENTER_CLOUDS_INITIAL_SCALE + (CENTER_CLOUDS_FINAL_SCALE - CENTER_CLOUDS_INITIAL_SCALE) * scalePercent;} else {scale = CENTER_CLOUDS_INITIAL_SCALE;}float parallaxPercent = 0;boolean parallax = false;// Current y position of cloudsfloat dragYOffset = mParent.getTotalDragDistance() * dragPercent;// Position when should start parallax scrollingint startParallaxHeight = mParent.getTotalDragDistance() - mFrontCloudHeightCenter;if (dragYOffset > startParallaxHeight) {parallax = true;parallaxPercent = dragYOffset - startParallaxHeight;}float offsetX = (mScreenWidth / 2) - mFrontCloudWidthCenter;float offsetY = dragYOffset- (parallax ? mFrontCloudHeightCenter + parallaxPercent : mFrontCloudHeightCenter)+ (overdrag ? mTop : 0);float sx = overdrag ? scale + overdragPercent / 4 : scale;float sy = overdrag ? scale + overdragPercent / 2 : scale;if (isRefreshing && !overdrag) {if (checkCurrentAnimationPart(AnimationPart.FIRST)) {sx = scale - (getAnimationPartValue(AnimationPart.FIRST) / LOADING_ANIMATION_COEFFICIENT) / 8;} else if (checkCurrentAnimationPart(AnimationPart.SECOND)) {sx = scale - (getAnimationPartValue(AnimationPart.SECOND) / LOADING_ANIMATION_COEFFICIENT) / 8;} else if (checkCurrentAnimationPart(AnimationPart.THIRD)) {sx = scale + (getAnimationPartValue(AnimationPart.THIRD) / LOADING_ANIMATION_COEFFICIENT) / 6;} else if (checkCurrentAnimationPart(AnimationPart.FOURTH)) {sx = scale + (getAnimationPartValue(AnimationPart.FOURTH) / LOADING_ANIMATION_COEFFICIENT) / 6;}sy = sx;}matrix.postScale(sx, sy, mFrontCloudWidthCenter, mFrontCloudHeightCenter);matrix.postTranslate(offsetX, offsetY);canvas.drawBitmap(mFrontClouds, matrix, null);}private void drawJet(Canvas canvas) {Matrix matrix = mMatrix;matrix.reset();float dragPercent = mPercent;float rotateAngle = 0;// Check overdragif (dragPercent > 1.0f && !mEndOfRefreshing) {rotateAngle = (dragPercent % 1) * 10;dragPercent = 1.0f;}float offsetX = ((mScreenWidth * dragPercent) / 2) - mJetWidthCenter;float offsetY = mJetTopOffset+ (mParent.getTotalDragDistance() / 2)* (1.0f - dragPercent)- mJetHeightCenter;if (isRefreshing) {if (checkCurrentAnimationPart(AnimationPart.FIRST)) {offsetY -= getAnimationPartValue(AnimationPart.FIRST);} else if (checkCurrentAnimationPart(AnimationPart.SECOND)) {offsetY -= getAnimationPartValue(AnimationPart.SECOND);} else if (checkCurrentAnimationPart(AnimationPart.THIRD)) {offsetY += getAnimationPartValue(AnimationPart.THIRD);} else if (checkCurrentAnimationPart(AnimationPart.FOURTH)) {offsetY += getAnimationPartValue(AnimationPart.FOURTH);}}matrix.setTranslate(offsetX, offsetY);if (dragPercent == 1.0f) {matrix.preRotate(rotateAngle, mJetWidthCenter, mJetHeightCenter);}canvas.drawBitmap(mJet, matrix, null);}

动画效果已经画好了,下面我们来看看怎么结合下拉刷新来调用吧?

二、我们还需要自定义一个PullToRefreshView(下拉刷新)

1.我们的PullToRefreshView这里需要继承ViewGroup

我们先把刚才定义的刷新时的动画加进来
private RefreshView mRefreshView;
<pre name="code" class="java">private ImageView mRefreshImageView;
<pre name="code" class="java">mRefreshImageView = new ImageView(context);mRefreshView = new RefreshView(getContext(), this);mRefreshImageView.setImageDrawable(mRefreshView);addView(mRefreshImageView);

2.然后我们设置OntouchEvent()事件

@Overridepublic boolean onTouchEvent(@NonNull MotionEvent ev) {if (!mIsBeingDragged) {return super.onTouchEvent(ev);}final int action = MotionEventCompat.getActionMasked(ev);switch (action) {case MotionEvent.ACTION_MOVE: {final int pointerIndex = MotionEventCompat.findPointerIndex(ev, mActivePointerId);if (pointerIndex < 0) {return false;}final float y = MotionEventCompat.getY(ev, pointerIndex);final float yDiff = y - mInitialMotionY;final float scrollTop = yDiff * DRAG_RATE;mCurrentDragPercent = scrollTop / mTotalDragDistance;if (mCurrentDragPercent < 0) {return false;}float boundedDragPercent = Math.min(1f, Math.abs(mCurrentDragPercent));float extraOS = Math.abs(scrollTop) - mTotalDragDistance;float slingshotDist = mTotalDragDistance;float tensionSlingshotPercent = Math.max(0,Math.min(extraOS, slingshotDist * 2) / slingshotDist);float tensionPercent = (float) ((tensionSlingshotPercent / 4) - Math.pow((tensionSlingshotPercent / 4), 2)) * 2f;float extraMove = (slingshotDist) * tensionPercent / 2;int targetY = (int) ((slingshotDist * boundedDragPercent) + extraMove);mRefreshView.setPercent(mCurrentDragPercent);setTargetOffsetTop(targetY - mCurrentOffsetTop, true);break;}case MotionEventCompat.ACTION_POINTER_DOWN:final int index = MotionEventCompat.getActionIndex(ev);mActivePointerId = MotionEventCompat.getPointerId(ev, index);break;case MotionEventCompat.ACTION_POINTER_UP:onSecondaryPointerUp(ev);break;case MotionEvent.ACTION_UP:case MotionEvent.ACTION_CANCEL: {if (mActivePointerId == INVALID_POINTER) {return false;}final int pointerIndex = MotionEventCompat.findPointerIndex(ev, mActivePointerId);final float y = MotionEventCompat.getY(ev, pointerIndex);final float overScrollTop = (y - mInitialMotionY) * DRAG_RATE;mIsBeingDragged = false;if (overScrollTop > mTotalDragDistance) {setRefreshing(true, true);} else {mRefreshing = false;animateOffsetToPosition(mAnimateToStartPosition);}mActivePointerId = INVALID_POINTER;return false;}}return true;}

三、最后我们看怎样在Activity中使用这个下拉刷新控件

1.先看一下布局文件

这里是我们的下拉刷新空间嵌套着我们的ListView,然后我们再给ListView填充数据即可
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"xmlns:tools="http://schemas.android.com/tools"android:layout_width="match_parent"android:layout_height="match_parent"tools:context=".PullToRefreshActivity"><com.hankkin.AnimationPullToRefreshDemo.PullToRefreshViewandroid:id="@+id/pull_to_refresh"android:layout_width="match_parent"android:layout_height="match_parent"><ListViewandroid:id="@+id/list_view"android:divider="@null"android:dividerHeight="0dp"android:fadingEdge="none"android:layout_width="match_parent"android:layout_height="match_parent" /></com.hankkin.AnimationPullToRefreshDemo.PullToRefreshView></RelativeLayout>

2.为ListView填充数据

为了我们的效果比较好看,这里我们给ListView的每一个item填充不同的颜色,看起来会比较高大上。
Map<String, Integer> map;List<Map<String, Integer>> sampleList = new ArrayList<Map<String, Integer>>();int[] colors = {R.color.saffron,R.color.eggplant,R.color.sienna};int[] tripNames = {R.string.trip_to_india,R.string.trip_to_italy,R.string.trip_to_indonesia};for (int i = 0; i < tripNames.length; i++) {map = new HashMap<String, Integer>();map.put(SampleAdapter.KEY_NAME, tripNames[i]);map.put(SampleAdapter.KEY_COLOR, colors[i]);sampleList.add(map);}ListView listView = (ListView) findViewById(R.id.list_view);listView.setAdapter(new SampleAdapter(this, R.layout.list_item, sampleList));

3.最后,我们再设置一下下拉刷新的监听事件就OK了

mPullToRefreshView = (PullToRefreshView) findViewById(R.id.pull_to_refresh);mPullToRefreshView.setOnRefreshListener(new PullToRefreshView.OnRefreshListener() {@Overridepublic void onRefresh() {mPullToRefreshView.postDelayed(new Runnable() {@Overridepublic void run() {mPullToRefreshView.setRefreshing(false);}}, REFRESH_DELAY);}});

怎么样?有没有很高大上啊?

说明:
自定义View里面的一些动画效果,包括飞机的动画效果,风的动画效果和一些方法没有详细介绍,有兴趣的小伙伴可以到github上下载源码仔细研究一下,作者写的还是比较不错的,很佩服。如果一些小伙伴还没有用惯AndroidStudio,这里也有Idea版本的,用Eclise同样可以打开运行看效果的。
下载地址:

http://www.eoeandroid.com/thread-905093-1-1.html

Android源码解析--超好看的下拉刷新动画相关推荐

  1. android 文字fly动画,超好看的下拉刷新动画Android代码实现

    最近看到了好多高端.大气.上档次的动画效果,如果给你的项目中加上这些动画,相信你的app一定很优秀,今天给大家分析一下来自Yalantis的一个超好看的下拉刷新动画. 首先我们看一下效果如何: 怎么样 ...

  2. Android源码解析(一)动画篇-- Animator属性动画系统

    Android源码解析-动画篇 Android源码解析(一)动画篇-- Animator属性动画系统 Android源码解析(二)动画篇-- ObjectAnimator Android在3.0版本中 ...

  3. Android源码解析--AlertDialog及AlertDialog.Builder

    昨天晚上弄到很晚,简单的看了下Dialog的源码,说要分析下建造者模式,在dialog里面的应用其实是在AlertDialog中. 按照惯例,先看类说明: [java] view plaincopy ...

  4. Android自定义下拉刷新动画--仿百度外卖下拉刷新

    好久没写博客了,小编之前一段时间一直在找工作,从天津来到了我们的大帝都,感觉还不错.好了废话不多说了,开始我们今天的主题吧.现如今的APP各式各样,同样也带来了各种需求,一个下拉刷新都能玩出花样了,前 ...

  5. android listview下拉动画效果,Android开发中利用ListView实现一个渐变式的下拉刷新动画...

    Android开发中利用ListView实现一个渐变式的下拉刷新动画 发布时间:2020-11-23 16:50:31 来源:亿速云 阅读:80 作者:Leah 本篇文章给大家分享的是有关Androi ...

  6. Android高仿京东、天猫下拉刷新

    说到下拉刷新,相信大家都不陌生,现在基本上每个项目都会用到.我们公司的项目一直都是使用SwipeRefreshLayout,官方的Material Design风格,好用少Bug.现在下拉刷新大概有下 ...

  7. iOS 类似亲宝宝app下拉刷新动画效果

    iOS 类似亲宝宝app下拉刷新动画效果,最近看了下这种效果,感觉有点意思.于是就实现了一下. 方案一 采用两个背景View1.View2,三个球ball1,ball2,ball3,将ball1,ba ...

  8. php仿boss直聘,仿BOSS直聘APP下拉刷新动画实现

    转自微信公众号:iOS面向编码 BOSS直聘APP的下拉刷新动画蛮有趣的,我们来尝试实现一下. 先来看看最终效果: 关于实现思路: 实现思路这东西,并不是一成不变的,每个人心中都有自己喜欢的思想和套路 ...

  9. html js微信朋友圈下拉刷新效果,仿朋友圈下拉刷新动画(基础动画)

    示意图: 2.0.gif demo地址:仿朋友圈下拉刷新动画 动画的起源源于好奇 因为刚开是学动画,恨不得把所有的都实现一遍,试了一下微信朋友圈的下拉刷新动画. 如果ViewController的第一 ...

最新文章

  1. C#基础篇--文件(流)
  2. js调整数组某些元素到指定位置顺序_如何将一个 JavaScript 数组打乱顺序?
  3. OpenCV之imgproc 模块. 图像处理(4)直方图均衡化 直方图计算 直方图对比 反向投影 模板匹配
  4. Linux fork()函数底层CopyOnWrite写时复制实现原理剖析
  5. 玄元剑仙服务器列表为空,玄元剑仙3月11日维护更新公告
  6. 石子合并(GarsiaWachs算法)
  7. JavaScript面向对象——多继承的实现与理解
  8. 位图索引,数据库索引浅浅的学习
  9. 丰厚奖学金博士招生 | 澳大利亚OPTIMA 招募博士,多光谱时间序列数据的时空目标检测/分割方向...
  10. Excel之【保护工作表】功能(工具----保护) ------可以防止修改格式,删除行。只能在里面填写数据。
  11. java消除整型数组中重复的元素,排序后输出新数组
  12. Dubbo的架构体系
  13. TimescaleDB 简单试用
  14. 牛腩新闻发布系统—发布错误总结
  15. 9篇前沿文章 | 一览肿瘤基因组及多组学思路
  16. C语言表白流星(末尾附加下载地址)
  17. Ubuntu 修改DNS
  18. Python输出所有水仙花数(3种方法)
  19. 104键键盘布局高清示意图
  20. 七个实用的分布式开源框架

热门文章

  1. 燧石文学奖得主凌丽芬做客TutorABC云讲堂谈语言的力量
  2. 联想小新15安装双系统win10+ubuntu
  3. php樱花许愿树代码_怪事笔记
  4. unity+vscode 自动补全代码
  5. 苹果研发可弯曲电池技术 未来iOS设备会更薄更美观
  6. java计算机毕业设计Vue.js音乐播放器设计与实现源码+mysql数据库+系统+lw文档+部署
  7. win10系统vmware station分辨率问题
  8. python性能提升之字符串拼接、字节流拼接
  9. puppet学习(一)
  10. python xy打不开、没有关联程序_解决该文件没有与之关联的程序来执行该操作