VelocityTrackerView 是用 VelocityTracker 与 Scroller 实现View的滑动,继承自ViewGroup,对VelocityTracker,Scroller的学习做个笔记。
VelocityTrackerView.java
import java.util.ArrayList;
import android.content.Context;
import android.graphics.Color;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.view.VelocityTracker;
import android.view.View;
import android.view.ViewConfiguration;
import android.view.ViewGroup;
import android.widget.Scroller;
public class VelocityTrackerView extends ViewGroup {
public static final String TAG = "VelocityTrackerView";
public ArrayList<Position> viewPoints;
private VelocityTracker mVelocityTracker;
private int mMaximumVelocity;
private int mMinimumVelocity;
private Scroller mScroller;
private int mPointerId; // 触点ID
private void initOrResetVelocityTracker() {
if (mVelocityTracker == null) {
mVelocityTracker = VelocityTracker.obtain();
} else {
mVelocityTracker.clear();
}
}
public VelocityTrackerView(Context context, AttributeSet attrs) {
super(context, attrs);
initScrollView();
viewPoints = new ArrayList<Position>();
}
private void initVelocityTrackerIfNotExists() {
if (mVelocityTracker == null) {
mVelocityTracker = VelocityTracker.obtain();
}
}
private void recycleVelocityTracker() {
if (mVelocityTracker != null) {
mVelocityTracker.recycle();
mVelocityTracker = null;
}
}
private void initScrollView() {
mScroller = new Scroller(getContext());
setFocusable(true);
setDescendantFocusability(FOCUS_AFTER_DESCENDANTS);
setWillNotDraw(false);
final ViewConfiguration configuration = ViewConfiguration
.get(getContext());
mMinimumVelocity = configuration.getScaledMinimumFlingVelocity();
mMaximumVelocity = configuration.getScaledMaximumFlingVelocity();
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
measureChildren(MeasureSpec.UNSPECIFIED, MeasureSpec.UNSPECIFIED);
viewPoints.clear();
//水平排列
for (int i = 0; i < getChildCount(); i++) {
View v = getChildAt(i);
if (i == 0) {
Position p = new Position();
p.view = v;
p.x = 0;
p.y = 0;
viewPoints.add(p);
} else {
Position p = new Position();
p.view = v;
p.y = 0;
p.x = viewPoints.get(i - 1).x
+ viewPoints.get(i - 1).view.getWidth();
viewPoints.add(p);
}
}
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
}
@Override
protected void onLayout(boolean changed, int l, int t, int r, int b) {
for (int i = 0; i < getChildCount(); i++) {
View child = getChildAt(i);
child.setVisibility(View.VISIBLE);
Position p = viewPoints.get(i);
child.layout(p.x, p.y, p.x + child.getMeasuredWidth(),
p.y + child.getMeasuredHeight());
if (i % 2 == 1) {
child.setBackgroundColor(Color.parseColor("#FF666633"));
} else {
child.setBackgroundColor(Color.parseColor("#FFaa1122"));
}
}
}
float mLastMotionX;
@Override
public boolean onTouchEvent(MotionEvent event) {
initVelocityTrackerIfNotExists();
mVelocityTracker.addMovement(event);
final float x = event.getX();
final float y = event.getY();
if (event.getAction() == MotionEvent.ACTION_DOWN) {
mPointerId = event.getPointerId(0);
initOrResetVelocityTracker();
if (!mScroller.isFinished()) {
mScroller.abortAnimation(); //禁止滑动
}
mLastMotionX = x;
} else if (event.getAction() == MotionEvent.ACTION_UP) {
// 求伪瞬时速度
mVelocityTracker.computeCurrentVelocity(1000, mMaximumVelocity);
final int velocityX = (int) mVelocityTracker
.getXVelocity(mPointerId);
if ((Math.abs(velocityX) > mMinimumVelocity) && getChildCount() > 0) {
fling(-velocityX);
}
recycleVelocityTracker();
} else if (event.getAction() == MotionEvent.ACTION_MOVE) {
int deltaX = (int) (mLastMotionX - x);
mLastMotionX = x;
//随着手指滚动
scrollBy(deltaX, 0);
} else if (event.getAction() == MotionEvent.ACTION_CANCEL) {
recycleVelocityTracker();
}
return true;
}
/**
* 滑动
* @param velocityX
*/
public void fling(int velocityX) {
if (getChildCount() > 0) {
//设置Scroller的滑动参数
mScroller.fling(getScrollX(), getScrollY(), velocityX, 0, 0, 10000,
0, 0);
//这里必须调用postInvalidate()才能保证computeScroll()会被调用,否则不一定会刷新界面,看不到滚动效果
postInvalidate();
}
}
@Override
public void computeScroll() {
//先判断mScroller滚动是否完成
if (mScroller.computeScrollOffset()) {
int scrollX = getScrollX();
int scrollY = getScrollY();
int oldX = scrollX;
int oldY = scrollY;
int x = mScroller.getCurrX();
int y = mScroller.getCurrY();
scrollX = x;
scrollY = y;
scrollY = scrollY + 10;
//这里调用View的scrollTo()完成实际的滚动
scrollTo(scrollX, scrollY);
postInvalidate(); //这里必须调用postInvalidate()才能保证computeScroll()会被调用,否则不一定会刷新界面,看不到滚动效果
}
}
public class Position {
int x;
int y = 0;
int width;
View view;
}
}
xml中使用:
<com.example.cyclingimage.VelocityTrackerView
android:id="@+id/velocityTrackerView1"
android:layout_width="wrap_content"
android:layout_height="400dp"
android:layout_alignParentLeft="true"
android:layout_alignParentTop="true" >
<TextView
android:layout_width="300dp"
android:layout_height="400dp"
android:text="1" />
<TextView
android:layout_width="300dp"
android:layout_height="400dp"
android:text="2" />
<TextView
android:layout_width="300dp"
android:layout_height="400dp"
android:text="3" />
<TextView
android:layout_width="300dp"
android:layout_height="400dp"
android:text="4" />
<TextView
android:layout_width="300dp"
android:layout_height="400dp"
android:text="5" />
</com.example.cyclingimage.VelocityTrackerView>