无意间在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. linux下使用正确的用户名密码,本地无法连接mysql

    问题现象: Linux系统为CentOS 7.0 64位,通过IP远程mysql时,可以正常访问,确定账号密码没有问题.但是本地连接mysql时,提示ERROR 1045 (28000): Acces ...

  2. olcal数据库经典SQL语句大全

    基于olacle自带的表 第一篇 -----1.列出至少有一个员工的所有部门. oracle 一些经典sql第一篇 --------1.列出至少有一个员工的所有部门.---------  SQL> ...

  3. 你所不知道的SQL Server数据库启动过程(用户数据库加载过程的疑难杂症)

    前言 本篇主要是上一篇文章的补充篇,上一篇我们介绍了SQL Server服务启动过程所遇到的一些问题和解决方法,可点击查看,我们此篇主要介绍的是SQL Server启动过程中关于用户数据库加载的流程, ...

  4. PHP模拟发送POST请求之五curl基本使用和多线程优化

    今天来介绍PHP模拟发送POST请求的重型武器——cURL函数库的使用和其多线程的优化方法. 说起cURL函数,可谓是老生常谈,但网上许多资料都在关键部分语焉不详,列出一大堆手册上的东西,搞得我入门时 ...

  5. CSS中vw和vh单位的使用

    vw——viewpoint width,视窗宽度,1vw等于视窗宽度的1%: vh——viewpoint height,视窗高度,1vh等于视窗高度的1%:例子:http://tutorialzine ...

  6. ehcache的介绍和使用

    ehcache结合spring cache主要注解使用:@Cacheable,@CacheEvict,@CachePut 在语法和配置等方面的使用  可以参考以下网站: 1.非常详细的spring m ...

  7. poj 2195 KM算法

    题目链接:http://poj.org/problem?id=2195 KM算法模板~ 代码如下: #include "stdio.h" #include "string ...

  8. Swift学习笔记--变量与常量

    1.Swift是一门强类型语言,不能为变量赋予其自身数据类型之外的值: 2.声明变量使用var关键字,声明常量使用let关键字: 3.声明变量或常量时没有对其指定类型且赋予了初值,则编译器会自动推断常 ...

  9. db2 常用命令(二)

    1. 打开命令行窗口 #db2cmd 2. 打开控制中心 # db2cmd db2cc 3. 打开命令编辑器 db2cmd db2ce   ======脚本文件操作命令=======  -- 执行脚本 ...

  10. 微信支付.NET版开发总结(JS API),好多坑,适当精简

    前2天,做一个手机网页的微信支付的项目,费了好些周折,记录一下.接下来,按照开发步骤,细数一下,我遇到的那些坑. [坑1]官方邮件中下载的demo只有PHP版本,其他版本没有给链接.可能让人误以为只有 ...