http://www.2cto.com/kf/201401/270169.html
下面是网上滑动删除的例子。
package com.example.swipedismisslistview;
import android.content.Context;
import android.util.AttributeSet;
import android.util.Log;
import android.view.MotionEvent;
import android.view.VelocityTracker;
import android.view.View;
import android.view.ViewConfiguration;
import android.view.ViewGroup;
import android.widget.AdapterView;
import android.widget.ListView;
import com.nineoldandroids.animation.Animator;
import com.nineoldandroids.animation.AnimatorListenerAdapter;
import com.nineoldandroids.animation.ObjectAnimator;
import com.nineoldandroids.animation.ValueAnimator;
import com.nineoldandroids.view.ViewHelper;
import com.nineoldandroids.view.ViewPropertyAnimator;
public class SwipeDismissListView extends ListView {
/**
* 认为是用户滑动的最小距离
*/
private int mSlop;
/**
* 滑动的最小速度
*/
private int mMinFlingVelocity;
/**
* 滑动的最大速度
*/
private int mMaxFlingVelocity;
/**
* 执行动画的时间
*/
protected long mAnimationTime = 150;
/**
* 用来标记用户是否正在滑动中
*/
private boolean mSwiping;
/**
* 滑动速度检测类
*/
private VelocityTracker mVelocityTracker;
/**
* 手指按下的position
*/
private int mDownPosition;
/**
* 按下的item对应的View
*/
private View mDownView;
private float mDownX;
private float mDownY;
/**
* item的宽度
*/
private int mViewWidth;
/**
* 当ListView的Item滑出界面回调的接口
*/
private OnDismissCallback onDismissCallback;
/**
* 设置动画时间
*
* @param mAnimationTime
*/
public void setmAnimationTime(long mAnimationTime) {
this.mAnimationTime = mAnimationTime;
}
/**
* 设置删除回调接口
*
* @param onDismissCallback
*/
public void setOnDismissCallback(OnDismissCallback onDismissCallback) {
this.onDismissCallback = onDismissCallback;
}
public SwipeDismissListView(Context context) {
this(context, null);
}
public SwipeDismissListView(Context context, AttributeSet attrs) {
this(context, attrs, 0);
}
public SwipeDismissListView(Context context, AttributeSet attrs,
int defStyle) {
super(context, attrs, defStyle);
ViewConfiguration vc = ViewConfiguration.get(context);
mSlop = vc.getScaledTouchSlop();
mMinFlingVelocity = vc.getScaledMinimumFlingVelocity() * 8; // 获取滑动的最小速度
mMaxFlingVelocity = vc.getScaledMaximumFlingVelocity(); // 获取滑动的最大速度
}
@Override
public boolean onTouchEvent(MotionEvent ev) {
switch (ev.getAction()) {
case MotionEvent.ACTION_DOWN:
handleActionDown(ev);
break;
case MotionEvent.ACTION_MOVE:
return handleActionMove(ev);
case MotionEvent.ACTION_UP:
handleActionUp(ev);
break;
case MotionEvent.ACTION_CANCEL:
//什么时候会触发这个事件
//http://blog.csdn.net/ldwtill/article/details/10162819
//Log.i("zhouke", "cancel......action");
break;
}
return super.onTouchEvent(ev);
}
/**
* 按下事件处理
*
* @param ev
* @return
*/
private void handleActionDown(MotionEvent ev) {
mDownX = ev.getX();
mDownY = ev.getY();
mDownPosition = pointToPosition((int) mDownX, (int) mDownY);
if (mDownPosition == AdapterView.INVALID_POSITION) {
return;
}
mDownView = getChildAt(mDownPosition - getFirstVisiblePosition());
if (mDownView != null) {
mViewWidth = mDownView.getWidth();
}
// 加入速度检测
mVelocityTracker = VelocityTracker.obtain();
mVelocityTracker.addMovement(ev);
}
/**
* 处理手指滑动的方法
*
* @param ev
* @return
*/
private boolean handleActionMove(MotionEvent ev) {
if (mVelocityTracker == null || mDownView == null) {
return super.onTouchEvent(ev);
}
float deltaX = ev.getX() - mDownX;
float deltaY = ev.getY() - mDownY;
// X方向滑动的距离大于mSlop并且Y方向滑动的距离小于mSlop,表示可以滑动
if (Math.abs(deltaX) > mSlop && Math.abs(deltaY) < mSlop) {
mSwiping = true;
// 当手指滑动item,取消item的点击事件,不然我们滑动Item也伴随着item点击事件的发生
MotionEvent cancelEvent = MotionEvent.obtain(ev);
//int a=ev.getActionIndex() << MotionEvent.ACTION_POINTER_INDEX_SHIFT;
cancelEvent
.setAction(MotionEvent.ACTION_CANCEL
| (ev.getActionIndex() << MotionEvent.ACTION_POINTER_INDEX_SHIFT));
onTouchEvent(cancelEvent);
}
if (mSwiping) {
// 跟谁手指移动item
ViewHelper.setTranslationX(mDownView, deltaX);
// 透明度渐变
ViewHelper.setAlpha(
mDownView,
Math.max(0f,Math.min(1f, 1f - 2f * Math.abs(deltaX)/ mViewWidth)));
// 手指滑动的时候,返回true,表示SwipeDismissListView自己处理onTouchEvent,其他的就交给父类来处理
return true;
}
return super.onTouchEvent(ev);
}
/**
* 手指抬起的事件处理
*
* @param ev
*/
private void handleActionUp(MotionEvent ev) {
if (mVelocityTracker == null || mDownView == null || !mSwiping) {
return;
}
float deltaX = ev.getX() - mDownX;
// 通过滑动的距离计算出X,Y方向的速度
mVelocityTracker.computeCurrentVelocity(1000);
float velocityX = Math.abs(mVelocityTracker.getXVelocity());
float velocityY = Math.abs(mVelocityTracker.getYVelocity());
boolean dismiss = false; // item是否要滑出屏幕
boolean dismissRight = false;// 是否往右边删除
// 当拖动item的距离大于item的一半,item滑出屏幕
if (Math.abs(deltaX) > mViewWidth / 2) {
dismiss = true;
dismissRight = deltaX > 0;
Log.i("zhouke", "if....");
// 手指在屏幕滑动的速度在某个范围内,也使得item滑出屏幕
} else if (mMinFlingVelocity <= velocityX
&& velocityX <= mMaxFlingVelocity && velocityY < velocityX) {
dismiss = true;
dismissRight = mVelocityTracker.getXVelocity() > 0;
Log.i("zhouke", "else.... ");
}
if (dismiss) {
// AnimatorSet set = new AnimatorSet();
// set.playTogether(ObjectAnimator.ofFloat(mDownView,
// "translationX", dismissRight ? mViewWidth : -mViewWidth),
// ObjectAnimator.ofFloat(mDownView, "alpha", 0));
// set.setDuration(mAnimationTime).start();
// set.addListener(new AnimatorListenerAdapter() {
// @Override
// public void onAnimationEnd(Animator animation) {
// //Item滑出界面之后执行删除
// performDismiss(mDownView, mDownPosition);
// }
// });
ViewPropertyAnimator.animate(mDownView)
.translationX(dismissRight ? mViewWidth : -mViewWidth)
// X轴方向的移动距离
.alpha(0).setDuration(mAnimationTime)
.setListener(new AnimatorListenerAdapter() {
@Override
public void onAnimationEnd(Animator animation) {
// Item滑出界面之后执行删除
performDismiss(mDownView, mDownPosition);
}
});
} else {
// 将item滑动至开始位置
ViewPropertyAnimator.animate(mDownView).translationX(0).alpha(1)
.setDuration(mAnimationTime).setListener(null);
}
// 移除速度检测
if (mVelocityTracker != null) {
mVelocityTracker.recycle();
mVelocityTracker = null;
}
mSwiping = false;
}
/**
* 在此方法中执行item删除之后,其他的item向上或者向下滚动的动画,并且将position回调到方法onDismiss()中
*
* @param dismissView
* @param dismissPosition
*/
private void performDismiss(final View dismissView,
final int dismissPosition) {
final ViewGroup.LayoutParams lp = dismissView.getLayoutParams();// 获取item的布局参数
final int originalHeight = dismissView.getHeight();// item的高度
Log.i("zhouke", "originalHeight:"+originalHeight);
ValueAnimator animator = ValueAnimator.ofInt(originalHeight, 0)
.setDuration(mAnimationTime);
animator.start();
animator.addListener(new AnimatorListenerAdapter() {
@Override
public void onAnimationEnd(Animator animation) {
if (onDismissCallback != null) {
onDismissCallback.onDismiss(dismissPosition);
}
Log.i("zhouke", "animation end");
// 这段代码很重要,因为我们并没有将item从ListView中移除,而是将item的高度设置为0
// 所以我们在动画执行完毕之后将item设置回来
ViewHelper.setAlpha(dismissView, 1f);
ViewHelper.setTranslationX(dismissView, 0);
ViewGroup.LayoutParams lp = dismissView.getLayoutParams();
lp.height = originalHeight;
dismissView.setLayoutParams(lp);
}
});
animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator valueAnimator) {
// 这段代码的效果是ListView删除某item之后,其他的item向上滑动的效果
lp.height = (Integer) valueAnimator.getAnimatedValue();
Log.i("zhouke", "animation update"+lp.height);
dismissView.setLayoutParams(lp);
}
});
}
/**
* 删除的回调接口
*
* @author xiaanming
*
*/
public interface OnDismissCallback {
public void onDismiss(int dismissPosition);
}
}
另一个简单需求,把button 的宽度增加到500.
package com.example.swipedismisslistview;
import com.nineoldandroids.animation.IntEvaluator;
import com.nineoldandroids.animation.ValueAnimator;
import com.nineoldandroids.animation.ValueAnimator.AnimatorUpdateListener;
import android.app.Activity;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
public class Activity2 extends Activity implements OnClickListener {
private Button btn1;
@Override
protected void onCreate(Bundle savedInstanceState) {
setContentView(R.layout.layout2);
btn1=(Button) findViewById(R.id.button1);
btn1.setOnClickListener(this);
super.onCreate(savedInstanceState);
}
private void performAnimate(final View target, final int start, final int end) {
ValueAnimator valueAnimator = ValueAnimator.ofInt(1, 100);
valueAnimator.addUpdateListener(new AnimatorUpdateListener() {
//持有一个IntEvaluator对象,方便下面估值的时候使用
private IntEvaluator mEvaluator = new IntEvaluator();
@Override
public void onAnimationUpdate(ValueAnimator animator) {
//获得当前动画的进度值,整型,1-100之间
int currentValue = (Integer)animator.getAnimatedValue();
//Log.i("zhouke", "current value:"+currentValue+":"+Thread.currentThread().getName());
//计算当前进度占整个动画过程的比例,浮点型,0-1之间
float fraction = currentValue / 100f;
//这里我偷懒了,不过有现成的干吗不用呢
//直接调用整型估值器通过比例计算出宽度,然后再设给Button
Integer evaluate = mEvaluator.evaluate(fraction, start, end);
Log.i("zhouke", "fraction:"+fraction+"evaluate:"+evaluate);
target.getLayoutParams().width = evaluate;
target.requestLayout();
}
});
valueAnimator.setDuration(5000).start();
}
@Override
public void onClick(View v) {
if (v == btn1) {
performAnimate(btn1, btn1.getWidth(), 500);
}
}
}
文字增长:
mainactivity
package com.bear.risenumbertest;
import android.app.Activity;
import android.os.Bundle;
import android.widget.Toast;
import com.bear.risenumbertest.lib.RiseNumberTextView;
import com.bear.risenumbertest.lib.RiseNumberTextView.EndListener;
public class MainActivity extends Activity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
// 获取到RiseNumberTextView对象
RiseNumberTextView rnTextView = (RiseNumberTextView) findViewById(R.id.risenumber_textview);
// 设置数据
rnTextView.withNumber(2666.50f);
// 设置动画播放时间
rnTextView.setDuration(5000);
// 开始播放动画
rnTextView.start();
// 监听动画播放结束
rnTextView.setOnEnd(new EndListener() {
@Override
public void onEndFinish() {
Toast.makeText(MainActivity.this, "数据增长完毕...", Toast.LENGTH_SHORT).show();
}
});
}
}
package com.bear.risenumbertest.lib;
public interface RiseNumberBase {
public void start();
public RiseNumberTextView withNumber(float number);
public RiseNumberTextView withNumber(int number);
public RiseNumberTextView setDuration(long duration);
public void setOnEnd(RiseNumberTextView.EndListener callback);
}
package com.bear.risenumbertest.lib;
import android.content.Context;
import android.util.AttributeSet;
import android.util.Log;
import android.widget.TextView;
import com.nineoldandroids.animation.ValueAnimator;
import java.text.DecimalFormat;
public class RiseNumberTextView extends TextView implements RiseNumberBase {
private static final int STOPPED = 0;
private static final int RUNNING = 1;
private int mPlayingState = STOPPED;
private float number;
private float fromNumber;
private long duration = 1500;
/**
* 1.int 2.float
*/
private int numberType = 2;
private DecimalFormat fnum;
private EndListener mEndListener = null;
final static int[] sizeTable = { 9, 99, 999, 9999, 99999, 999999, 9999999, 99999999, 999999999, Integer.MAX_VALUE };
public RiseNumberTextView(Context context) {
super(context);
}
public RiseNumberTextView(Context context, AttributeSet attr) {
super(context, attr);
}
public RiseNumberTextView(Context context, AttributeSet attr, int defStyle) {
super(context, attr, defStyle);
}
public interface EndListener {
public void onEndFinish();
}
public boolean isRunning() {
return (mPlayingState == RUNNING);
}
private void runFloat() {
ValueAnimator valueAnimator = ValueAnimator.ofFloat(fromNumber, number);
valueAnimator.setDuration(duration);
valueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator valueAnimator) {
setText(fnum.format(Float.parseFloat(valueAnimator.getAnimatedValue().toString())));
if (valueAnimator.getAnimatedFraction() >= 1) {
mPlayingState = STOPPED;
if (mEndListener != null)
mEndListener.onEndFinish();
}
}
});
valueAnimator.start();
}
private void runInt() {
ValueAnimator valueAnimator = ValueAnimator.ofInt((int) fromNumber, (int) number);
valueAnimator.setDuration(duration);
valueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator valueAnimator) {
setText(valueAnimator.getAnimatedValue().toString());
if (valueAnimator.getAnimatedFraction() >= 1) {
mPlayingState = STOPPED;
if (mEndListener != null)
mEndListener.onEndFinish();
}
}
});
valueAnimator.start();
}
static int sizeOfInt(int x) {
for (int i = 0;; i++)
if (x <= sizeTable[i])
return i + 1;
}
@Override
protected void onFinishInflate() {
super.onFinishInflate();
fnum = new DecimalFormat("##0.00");
}
@Override
public void start() {
if (!isRunning()) {
mPlayingState = RUNNING;
if (numberType == 1)
runInt();
else
runFloat();
}
}
@Override
public RiseNumberTextView withNumber(float number) {
this.number = number;
numberType = 2;
if (number > 1000) {
Log.i("zhouke", "sizeofInt:"+(sizeOfInt((int)number)-2));
fromNumber = number - (float) Math.pow(10, sizeOfInt((int) number) - 2);
Log.i("zhouke", "1formaNumber:"+fromNumber+"number:"+number);
} else {
fromNumber = number / 2;
Log.i("zhouke", "2formaNumber:"+fromNumber);
}
return this;
}
@Override
public RiseNumberTextView withNumber(int number) {
this.number = number;
numberType = 1;
if (number > 1000) {
fromNumber = number - (float) Math.pow(10, sizeOfInt((int) number) - 2);
} else {
fromNumber = number / 2;
}
return this;
}
@Override
public RiseNumberTextView setDuration(long duration) {
this.duration = duration;
return this;
}
@Override
public void setOnEnd(EndListener callback) {
mEndListener = callback;
}
}
===========
ViewHelper.setRotationX(view, baseRotation);
ViewHelper.setTranslationY(view, fromY);
ViewPropertyAnimator
.animate(view)
.setInterpolator(new AccelerateDecelerateInterpolator())
.setDuration(duration)
.setStartDelay(startDelay)
.rotationX(0)
.translationY(0)
.start();