在Android开发过程中,有这样一个普遍的需求:用手指滑动一个View,当手离开屏幕后View还能滑动一定的距离。
要完成这样的效果只需两步:1.获取手指离开时的速度。2.使View滚动一定的距离。
一、获取Touch事件的速度
通过VelocityTracker可以获得Touch事件的速度,VelocityTracker这个类使用比较简单,方法很少,常用的方法如下:
<span style="font-family:KaiTi_GB2312;font-size:14px;">//获取一个VelocityTracker对象
static public VelocityTracker obtain();
//在Touch的down和move事件中把Touch加入到VelocityTracker对象中
void android.view.VelocityTracker.addMovement(MotionEvent event)
//计算当前速度, 其中units是单位表示, 1代表px/毫秒, 1000代表px/秒
//maxVelocity此次计算速度你想要的最大值
public void computeCurrentVelocity(int units, float maxVelocity);
//经过一次computeCurrentVelocity后你就可以用一下几个方法获取此次计算的值
//id是touch event触摸点的ID, 来为多点触控标识
public float getXVelocity();
public float getYVelocity();
public float getXVelocity(int id);
public float getYVelocity(int id);
//用完后记得回收,回收后代表你不需要使用了,系统将此对象在此分配到其他请求者
public void recycle();</span>
二、使View滚动一定的距离。
实现这个效果一般就是使用Scroller的fling方法 +(scrollTo或者scrollBy),如果你的View有其他需求,自行实现就可以了。关于Scroller怎么使用这里就不介绍了。
下面是一个简单的Demo:
public class ScrollLinearLayout extends LinearLayout {
private Scroller mScroller;
private VelocityTracker mVelocityTracker;
public ScrollLinearLayout(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
init(context);
}
public ScrollLinearLayout(Context context, AttributeSet attrs) {
super(context, attrs);
init(context);
}
public ScrollLinearLayout(Context context) {
super(context);
init(context);
}
private void init(Context context) {
setOrientation(HORIZONTAL);
mScroller = new Scroller(context);
}
private float xLastLocation, yLastLocation;
public boolean onTouchEvent(MotionEvent event) {
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
addVelocityTracker(event);
xLastLocation = event.getX();
yLastLocation = event.getY();
break;
case MotionEvent.ACTION_MOVE:
addVelocityTracker(event);
float xCurrentLocation = event.getX();
float yCurrentLocation = event.getY();
float xMove = xCurrentLocation - xLastLocation;
float yMove = yCurrentLocation - yLastLocation;
xLastLocation = xCurrentLocation;
yLastLocation = yCurrentLocation;
scrollBy(-(int) xMove, -(int) yMove);
break;
case MotionEvent.ACTION_UP:
// 在触点抬起后再继续滑动一定距离
int xVelocity = getXScrollVelocity();
int yVelocity = getYScrollVelocity();
mScroller.forceFinished(true);
mScroller.fling(getScrollX(), getScrollY(), (int) (-0.5 * xVelocity), (int) (-0.5 * yVelocity), -2000, 2000, -2000, 2000);
recycleVelocityTracker();
break;
}
invalidate();
return true;
}
@Override
public void computeScroll() {
if (mScroller.computeScrollOffset()) {
scrollTo(mScroller.getCurrX(), mScroller.getCurrY());
postInvalidate();
}
}
/**
* 添加用户的速度跟踪器
*/
private void addVelocityTracker(MotionEvent event) {
if (mVelocityTracker == null) {
mVelocityTracker = VelocityTracker.obtain();
}
mVelocityTracker.addMovement(event);
}
/**
* 移除用户速度跟踪器
*/
private void recycleVelocityTracker() {
if (mVelocityTracker != null) {
mVelocityTracker.recycle();
mVelocityTracker = null;
}
}
/**
* 获取X方向的滑动速度,大于0向右滑动,反之向左
*/
private int getXScrollVelocity() {
mVelocityTracker.computeCurrentVelocity(1000);
int velocity = (int) mVelocityTracker.getXVelocity();
return velocity;
}
/**
* 获取Y方向的滑动速度,大于0向下滑动,反之向上
*/
private int getYScrollVelocity() {
mVelocityTracker.computeCurrentVelocity(1000);
int velocity = (int) mVelocityTracker.getYVelocity();
return velocity;
}
}