无意间在GitHub看到的,就Down了下来。但是作者是用AndroidStudio开发的,这边移动Eclipse供小伙伴们下载使用。

截图

这么好的东西因为字数不够不让分享,得了,贴段代码吧

package com.example.pullrefersh;

import android.content.Context;
import android.content.res.TypedArray;
import android.support.v4.view.MotionEventCompat;
import android.support.v4.view.ViewCompat;
import android.util.AttributeSet;
import android.util.TypedValue;
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewConfiguration;
import android.view.ViewGroup;
import android.view.animation.Animation;
import android.view.animation.DecelerateInterpolator;
import android.view.animation.Interpolator;
import android.view.animation.Transformation;
import android.widget.AbsListView;
import android.widget.ImageView; import java.security.InvalidParameterException; import refresh_view.BaseRefreshView;
import refresh_view.SunRefreshView;
import util.Utils; public class PullToRefreshView extends ViewGroup { private static final int DRAG_MAX_DISTANCE = 120;
private static final float DRAG_RATE = .5f;
private static final float DECELERATE_INTERPOLATION_FACTOR = 2f; public static final int STYLE_SUN = 0;
public static final int STYLE_JET = 1;
public static final int MAX_OFFSET_ANIMATION_DURATION = 700; private static final int INVALID_POINTER = -1; private View mTarget;
private ImageView mRefreshView;
private Interpolator mDecelerateInterpolator;
private int mTouchSlop;
private int mTotalDragDistance;
private BaseRefreshView mBaseRefreshView;
private float mCurrentDragPercent;
private int mCurrentOffsetTop;
private boolean mRefreshing;
private int mActivePointerId;
private boolean mIsBeingDragged;
private float mInitialMotionY;
private int mFrom;
private float mFromDragPercent;
private boolean mNotify;
private OnRefreshListener mListener; public PullToRefreshView(Context context) {
this(context, null);
} public PullToRefreshView(Context context, AttributeSet attrs) {
super(context, attrs);
TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.RefreshView);
final int type = a.getInteger(R.styleable.RefreshView_type, STYLE_SUN);
a.recycle(); mDecelerateInterpolator = new DecelerateInterpolator(DECELERATE_INTERPOLATION_FACTOR);
mTouchSlop = ViewConfiguration.get(context).getScaledTouchSlop();
mTotalDragDistance = Utils.convertDpToPixel(context, DRAG_MAX_DISTANCE); mRefreshView = new ImageView(context); setRefreshStyle(type); addView(mRefreshView); setWillNotDraw(false);
// ViewCompat.setChildrenDrawingOrderEnabled(this, true);
} public void setRefreshStyle(int type) {
setRefreshing(false);
switch (type) {
case STYLE_SUN:
mBaseRefreshView = new SunRefreshView(getContext(), this);
break;
case STYLE_JET:
// TODO
default:
throw new InvalidParameterException("Type does not exist");
}
mRefreshView.setImageDrawable(mBaseRefreshView);
} public int getTotalDragDistance() {
return mTotalDragDistance;
} @Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec); ensureTarget();
if (mTarget == null)
return; widthMeasureSpec = MeasureSpec.makeMeasureSpec(getMeasuredWidth() - getPaddingRight() - getPaddingLeft(), MeasureSpec.EXACTLY);
heightMeasureSpec = MeasureSpec.makeMeasureSpec(getMeasuredHeight() - getPaddingTop() - getPaddingBottom(), MeasureSpec.EXACTLY);
mTarget.measure(widthMeasureSpec, heightMeasureSpec);
mRefreshView.measure(widthMeasureSpec, heightMeasureSpec);
} private void ensureTarget() {
if (mTarget != null)
return;
if (getChildCount() > 0) {
for (int i = 0; i < getChildCount(); i++) {
View child = getChildAt(i);
if (child != mRefreshView)
mTarget = child;
}
}
} @Override
public boolean onInterceptTouchEvent(MotionEvent ev) { if (!isEnabled() || canChildScrollUp() || mRefreshing) {
return false;
} final int action = MotionEventCompat.getActionMasked(ev); switch (action) {
case MotionEvent.ACTION_DOWN:
setTargetOffsetTop(0, true);
mActivePointerId = MotionEventCompat.getPointerId(ev, 0);
mIsBeingDragged = false;
final float initialMotionY = getMotionEventY(ev, mActivePointerId);
if (initialMotionY == -1) {
return false;
}
mInitialMotionY = initialMotionY;
break;
case MotionEvent.ACTION_MOVE:
if (mActivePointerId == INVALID_POINTER) {
return false;
}
final float y = getMotionEventY(ev, mActivePointerId);
if (y == -1) {
return false;
}
final float yDiff = y - mInitialMotionY;
if (yDiff > mTouchSlop && !mIsBeingDragged) {
mIsBeingDragged = true;
}
break;
case MotionEvent.ACTION_UP:
case MotionEvent.ACTION_CANCEL:
mIsBeingDragged = false;
mActivePointerId = INVALID_POINTER;
break;
case MotionEventCompat.ACTION_POINTER_UP:
onSecondaryPointerUp(ev);
break;
} return mIsBeingDragged;
} @Override
public boolean onTouchEvent(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); mBaseRefreshView.setPercent(mCurrentDragPercent, true);
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;
animateOffsetToStartPosition();
}
mActivePointerId = INVALID_POINTER;
return false;
}
} return true;
} private void animateOffsetToStartPosition() {
mFrom = mCurrentOffsetTop;
mFromDragPercent = mCurrentDragPercent;
long animationDuration = Math.abs((long) (MAX_OFFSET_ANIMATION_DURATION * mFromDragPercent)); mAnimateToStartPosition.reset();
mAnimateToStartPosition.setDuration(animationDuration);
mAnimateToStartPosition.setInterpolator(mDecelerateInterpolator);
mAnimateToStartPosition.setAnimationListener(mToStartListener);
mRefreshView.clearAnimation();
mRefreshView.startAnimation(mAnimateToStartPosition);
} private void animateOffsetToCorrectPosition() {
mFrom = mCurrentOffsetTop;
mFromDragPercent = mCurrentDragPercent; mAnimateToCorrectPosition.reset();
mAnimateToCorrectPosition.setDuration(MAX_OFFSET_ANIMATION_DURATION);
mAnimateToCorrectPosition.setInterpolator(mDecelerateInterpolator);
mRefreshView.clearAnimation();
mRefreshView.startAnimation(mAnimateToCorrectPosition); if (mRefreshing) {
mBaseRefreshView.start();
if (mNotify) {
if (mListener != null) {
mListener.onRefresh();
}
}
} else {
mBaseRefreshView.stop();
animateOffsetToStartPosition();
}
mCurrentOffsetTop = mTarget.getTop();
} private final Animation mAnimateToStartPosition = new Animation() {
@Override
public void applyTransformation(float interpolatedTime, Transformation t) {
moveToStart(interpolatedTime);
}
}; private final Animation mAnimateToCorrectPosition = new Animation() {
@Override
public void applyTransformation(float interpolatedTime, Transformation t) {
int targetTop;
int endTarget = mTotalDragDistance;
targetTop = (mFrom + (int) ((endTarget - mFrom) * interpolatedTime));
int offset = targetTop - mTarget.getTop(); mCurrentDragPercent = mFromDragPercent - (mFromDragPercent - 1.0f) * interpolatedTime;
mBaseRefreshView.setPercent(mCurrentDragPercent, false); setTargetOffsetTop(offset, false /* requires update */);
}
}; private void moveToStart(float interpolatedTime) {
int targetTop = mFrom - (int) (mFrom * interpolatedTime);
float targetPercent = mFromDragPercent * (1.0f - interpolatedTime);
int offset = targetTop - mTarget.getTop(); mCurrentDragPercent = targetPercent;
mBaseRefreshView.setPercent(mCurrentDragPercent, true);
setTargetOffsetTop(offset, false);
} public void setRefreshing(boolean refreshing) {
if (mRefreshing != refreshing) {
setRefreshing(refreshing, false /* notify */);
}
} private void setRefreshing(boolean refreshing, final boolean notify) {
if (mRefreshing != refreshing) {
mNotify = notify;
ensureTarget();
mRefreshing = refreshing;
if (mRefreshing) {
mBaseRefreshView.setPercent(1f, true);
animateOffsetToCorrectPosition();
} else {
animateOffsetToStartPosition();
}
}
} private Animation.AnimationListener mToStartListener = new Animation.AnimationListener() {
@Override
public void onAnimationStart(Animation animation) {
} @Override
public void onAnimationRepeat(Animation animation) {
} @Override
public void onAnimationEnd(Animation animation) {
mBaseRefreshView.stop();
mCurrentOffsetTop = mTarget.getTop();
}
}; private void onSecondaryPointerUp(MotionEvent ev) {
final int pointerIndex = MotionEventCompat.getActionIndex(ev);
final int pointerId = MotionEventCompat.getPointerId(ev, pointerIndex);
if (pointerId == mActivePointerId) {
final int newPointerIndex = pointerIndex == 0 ? 1 : 0;
mActivePointerId = MotionEventCompat.getPointerId(ev, newPointerIndex);
}
} private float getMotionEventY(MotionEvent ev, int activePointerId) {
final int index = MotionEventCompat.findPointerIndex(ev, activePointerId);
if (index < 0) {
return -1;
}
return MotionEventCompat.getY(ev, index);
} private void setTargetOffsetTop(int offset, boolean requiresUpdate) {
mTarget.offsetTopAndBottom(offset);
mBaseRefreshView.offsetTopAndBottom(offset);
mCurrentOffsetTop = mTarget.getTop();
if (requiresUpdate && android.os.Build.VERSION.SDK_INT < 11) {
invalidate();
}
} private boolean canChildScrollUp() {
if (android.os.Build.VERSION.SDK_INT < 14) {
if (mTarget instanceof AbsListView) {
final AbsListView absListView = (AbsListView) mTarget;
return absListView.getChildCount() > 0
&& (absListView.getFirstVisiblePosition() > 0 || absListView.getChildAt(0)
.getTop() < absListView.getPaddingTop());
} else {
return mTarget.getScrollY() > 0;
}
} else {
return ViewCompat.canScrollVertically(mTarget, -1);
}
} @Override
protected void onLayout(boolean changed, int l, int t, int r, int b) { ensureTarget();
if (mTarget == null)
return; int height = getMeasuredHeight();
int width = getMeasuredWidth();
int left = getPaddingLeft();
int top = getPaddingTop();
int right = getPaddingRight();
int bottom = getPaddingBottom(); mTarget.layout(left, top + mCurrentOffsetTop, left + width - right, top + height - bottom + mCurrentOffsetTop);
mRefreshView.layout(left, top, left + width - right, top + height - bottom);
} public void setOnRefreshListener(OnRefreshListener listener) {
mListener = listener;
} public static interface OnRefreshListener {
public void onRefresh();
} }

下载地址:http://download.csdn.net/detail/lj419855402/8421179

一款Android开源的下拉刷新动画的更多相关文章

  1. Android PullToRrefresh 自定义下拉刷新动画 (listview、scrollview等)

    PullToRefreshScrollView 自定义下拉刷新动画,只需改一处. 以下部分转载自http://blog.csdn.net/superjunjin/article/details/450 ...

  2. Android内置下拉刷新组件SwipeRefreshLayout

    也许下拉刷新之前,你可能会使用一些第三方的开源库,例如PullToRefresh, ActionBar-PullToRefresh等待,但现在有的正式组成部分---SwipeRefreshLayout ...

  3. Android之XListView下拉刷新,更新网络美女图

    一.简介:   下拉刷新是一种特定的手动刷新交互,和其他的同类操作不同的地方在于它采用了更加直觉的下拉操作,所以它的交互足够清晰明显. 下拉刷新主要用在类似ListView这样的控件,设计下拉刷新有三 ...

  4. Android之自定义控件-下拉刷新

    实现效果: 图片素材:         --> 首先, 写先下拉刷新时的刷新布局 pull_to_refresh.xml: <resources> <string name=& ...

  5. Android SwipeRefreshLayout 官方下拉刷新控件介绍

    转载请标明出处:http://blog.csdn.net/lmj623565791/article/details/24521483 下面App基本都有下拉刷新的功能,以前基本都使用XListView ...

  6. 【转载】Android中ListView下拉刷新的实现

    在网上看到一个下拉刷新的例子,很的很棒,转载和更多的人分享学习 原文:http://blog.csdn.net/loongggdroid/article/details/9385535 ListVie ...

  7. Android中ListView下拉刷新的实现

    ListView中的下拉刷新是非常常见的,也是经常使用的,看到有很多同学想要,那我就整理一下,供大家参考.那我就不解释,直接上代码了. 这里需要自己重写一下ListView,重写代码如下: packa ...

  8. Android之SwipeRefreshLayout下拉刷新组件

    SwipeRefreshLayout概述 SwipeRefrshLayout是Google官方更新的一个Widget,可以实现下拉刷新的效果.该控件集成自ViewGroup在support-v4兼容包 ...

  9. Android中实现下拉刷新

    需求:项目中的消息列表界面要求实现类似sina微博的下拉刷新: 思路:一般的消息列表为ListView类型,将list加载到adapter中,再将adapter加载到 ListView中,从而实现消息 ...

随机推荐

  1. 学习C语言的数组

    C语言的数组 数组声明的实例:int num[3];只要记下这个模板就好. 不建议使用变量定义数组,如果使用了变量定义数组,作为数组的元素的个数,不初始化的情况下是随机值,如果初始化会直接报错 注意: ...

  2. android 开发小记

    1.fragment & activity when config changes, activity will restart but fragment can be store. 2.te ...

  3. MongoDb的bin目录下文件mongod,mongo,mongostat命令的说明及使用

    MongoDB的下载地址:http://www.mongodb.org/downloads. 下载好直接解压安装包,即可使用. bin目录下的几个文件说明: mongo 客户端程序,连接MongoDB ...

  4. 百度推出的echarts,制表折线图柱状图饼图等的超级工具(转)

    一.简介: 1.绘制数据图表,有了它,想要网页上绘制个折线图.柱状图,从此easy. 2.使用这个百度的echarts.js插件,是通过把图片绘制在canvas上在显示在页面上. 官网对echarts ...

  5. HTML5 datalist 标签

    以前需要用JS写一个自动完成组件(Suggest),很费劲.HTML5时代则不用了,直接使用datalist标签,直接减少了工作量.如下 <!DOCTYPE html> <html& ...

  6. JavaScript生成GUID的算法

    全局唯一标识符(GUID,Globally Unique Identifier)也称作 UUID(Universally Unique IDentifier) . GUID是一种由算法生成的二进制长度 ...

  7. Linux shell misc

    sometimes you will write shell in windows platform, be careful for this, adjust the notepad plus plu ...

  8. 解决客户端通过zookeeper连接到hbase时连接过多的问题

    原因:客户端程序通过zookeeper访问hbase的连接数超过设置的默认链接数(默认数是30),连接数不够用会导致后续的连接连接不上去. 解决办法:设置hbase-site.xml配置文件,添加如下 ...

  9. NOIP2010普及组T3 接水问题 ——S.B.S.

    题目描述 学校里有一个水房,水房里一共装有 m 个龙头可供同学们打开水,每个龙头每秒钟的 供水量相等,均为 1. 现在有 n 名同学准备接水,他们的初始接水顺序已经确定.将这些同学按接水顺序从 1到 ...

  10. TestNG之参数化

    TestNG提供了两种参数化的方式,一种是通过XML,一种是通过代码实现,下面对这两种方式做介绍. 一.通过xml /** * <suite name="Suite" par ...