超好看的下拉刷新动画Android代码实现

最近看到了好多高端、大气、上档次的动画效果,如果给你的项目中加上这些动画,相信你的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 wind while (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 winds if (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 distance if (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 wind if (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 winds if (mInverseDirection && mNewWindSet) { mWinds.clear(); mNewWindSet = false; mWindLineWidth = random(MIN_WIND_LINE_WIDTH, MAX_WIND_LINE_WIDTH); } // needed for checking direction mLastAnimationTime = 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 time Removing 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 ANIMATION if (mLastAnimationTime - mLoadingAnimationTime > 0) { mInverseDirection = true; // take time from 0 to end of animation time time = (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 width float 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 here float dragPercent = Math.min(1f, Math.abs(mPercent)); boolean overdrag = false; // But we check here for overdrag if (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 clouds float dragYOffset = mParent.getTotalDragDistance() * (1.0f - dragPercent); // Position where clouds fully visible on screen and we should drag them with content of listView int 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 process if (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 done overdragPercent = 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 clouds float dragYOffset = mParent.getTotalDragDistance() * dragPercent; // Position when should start parallax scrolling int 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 overdrag if (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()事件

@Override public 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.PullToRefreshView android:id="@+id/pull_to_refresh" android:layout_width="match_parent" android:layout_height="match_parent"> <ListView android: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() { @Override public void onRefresh() { mPullToRefreshView.postDelayed(new Runnable() { @Override public void run() { mPullToRefreshView.setRefreshing(false); } }, REFRESH_DELAY); } });

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

大家可以动手实践一下,希望对大家的学习有所帮助。

时间: 2024-08-01 18:45:24

超好看的下拉刷新动画Android代码实现的相关文章

超好看的下拉刷新动画Android代码实现_Android

最近看到了好多高端.大气.上档次的动画效果,如果给你的项目中加上这些动画,相信你的app一定很优秀,今天给大家分析一下来自Yalantis的一个超好看的下拉刷新动画. 首先我们看一下效果如何: 怎么样?是不是很高大上?接下来我们看一下代码: 一.首先我们需要自定义刷新的动态RefreshView(也就是下拉时候的头)1.初始化头所占用的Dimens private void initiateDimens() { mScreenWidth = mContext.getResources().get

Android使用PullToRefresh实现上拉加载和下拉刷新效果的代码_Android

在没给大家介绍正文之前,先给大家介绍展示下运行图,如果大家感觉还不错,请继续往下阅读: 相关阅读:分享Android中pullToRefresh的使用心得 项目已同步至:https://github.com/nanchen2251/pullToRefreshDemo 简单使用详情: 1)studio可以直接在app的module设置中直接进行搜索,但是有-的必须添上,而不能用空格代替,为了更加了解这个东西,我还是推荐大家去这里看看,奉上网址: https://github.com/chrisba

Android使用PullToRefresh实现上拉加载和下拉刷新效果的代码

在没给大家介绍正文之前,先给大家介绍展示下运行图,如果大家感觉还不错,请继续往下阅读: 相关阅读:分享Android中pullToRefresh的使用心得 项目已同步至:https://github.com/nanchen2251/pullToRefreshDemo 简单使用详情: 1)studio可以直接在app的module设置中直接进行搜索,但是有-的必须添上,而不能用空格代替,为了更加了解这个东西,我还是推荐大家去这里看看,奉上网址: https://github.com/chrisba

Android中ListView下拉刷新的实现代码

Android中ListView下拉刷新 实现效果图: ListView中的下拉刷新是非常常见的,也是经常使用的,看到有很多同学想要,那我就整理一下,供大家参考.那我就不解释,直接上代码了. 这里需要自己重写一下ListView,重写代码如下: package net.loonggg.listview; import java.util.Date; import android.content.Context; import android.util.AttributeSet; import a

Android下拉刷新框架实现代码实例_Android

前段时间项目中用到了下拉刷新功能,之前在网上也找到过类似的demo,但这些demo的质量参差不齐,用户体验也不好,接口设计也不行.最张没办法,终于忍不了了,自己就写了一个下拉刷新的框架,这个框架是一个通用的框架,效果和设计感觉都还不错,现在分享给各位看官. 一. 关于下拉刷新 下拉刷新这种用户交互最早由twitter创始人洛伦•布里切特(Loren Brichter)发明,有理论认为,下拉刷新是一种适用于按照从新到旧的时间顺序排列feeds的应用,在这种应用场景中看完旧的内容时,用户会很自然地下

Android自定义渐变式炫酷ListView下拉刷新动画

本文实例为大家分享了自定义渐变式炫酷动画的ListView下拉刷新,供大家参考,具体内容如下 主要要点 listview刷新过程中主要有三个步骤当前:状态为下拉刷新,当前状态为下拉刷新,当前状态为放开刷新,当前状态为正在刷新:主要思路为三个步骤分别对应三个自定义的view:即ibuRefreshFirstStepView,ibuRefreshSecondStepView,ibuRefreshThirdStepView. 效果图 ibuRefreshFirstStepView代码,例如: priv

Android下拉刷新框架实现代码实例

前段时间项目中用到了下拉刷新功能,之前在网上也找到过类似的demo,但这些demo的质量参差不齐,用户体验也不好,接口设计也不行.最张没办法,终于忍不了了,自己就写了一个下拉刷新的框架,这个框架是一个通用的框架,效果和设计感觉都还不错,现在分享给各位看官. 一. 关于下拉刷新 下拉刷新这种用户交互最早由twitter创始人洛伦•布里切特(Loren Brichter)发明,有理论认为,下拉刷新是一种适用于按照从新到旧的时间顺序排列feeds的应用,在这种应用场景中看完旧的内容时,用户会很自然地下

下拉刷新问题-android下拉刷新有时候拉不出来问题

问题描述 android下拉刷新有时候拉不出来问题 这个下拉在1位置有时候拉的下来 有时候拉不下来(代码没动的情况下),2位置拉的话就一切正常 什么原因呢 求大神解答 解决方案 应该是焦点覆盖问题,你重写一下onTouch监听事件 解决方案二: 你用的是XListView还是PullToRefresh?

android PullToRrefresh自定义下拉刷新动画

参考自 http://blog.csdn.net/wwj_748/article/details/42523611 首先,下载著名的刷新框架https://github.com/chrisbanes/Android-PullToRefresh,其中simple为demo,library和extras作为项目包导入到simple中 一,定义刷新动画的layout 在library下的com.handmark.pulltorefresh.library.internal包中的FlipLoadingL