您的位置:首页 > 移动开发 > Android开发

Android Scroller的理解

2013-12-22 16:54 260 查看
要理解Android的原理,最好的方法是通过源码来分析。这次又来了,看看Scroller到底是什么?

Scroller就是一个滚动的辅助类,它只存储View的位置和计算出位置,并没有真正移动View,讨厌的是Scroller.startScroll()从名字上误导人了,刚开始还以为是这个方法移动的呢。

public class Scroller {
private int mMode;

private int mStartX;
private int mStartY;
private int mFinalX;
private int mFinalY;

private int mMinX;
private int mMaxX;
private int mMinY;
private int mMaxY;

private int mCurrX;
private int mCurrY;
private long mStartTime;
private int mDuration;
private float mDurationReciprocal;
private float mDeltaX;
private float mDeltaY;
private boolean mFinished;
private Interpolator mInterpolator;
private boolean mFlywheel;

private float mVelocity;
private float mCurrVelocity;
private int mDistance;

private float mFlingFriction = ViewConfiguration.getScrollFriction();

private static final int DEFAULT_DURATION = 250;
private static final int SCROLL_MODE = 0;
private static final int FLING_MODE = 1;

private static float DECELERATION_RATE = (float) (Math.log(0.78) / Math.log(0.9));
private static final float INFLEXION = 0.35f; // Tension lines cross at (INFLEXION, 1)
private static final float START_TENSION = 0.5f;
private static final float END_TENSION = 1.0f;
private static final float P1 = START_TENSION * INFLEXION;
private static final float P2 = 1.0f - END_TENSION * (1.0f - INFLEXION);

private static final int NB_SAMPLES = 100;
private static final float[] SPLINE_POSITION = new float[NB_SAMPLES + 1];
private static final float[] SPLINE_TIME = new float[NB_SAMPLES + 1];

private float mDeceleration;
private final float mPpi;

// A context-specific coefficient adjusted to physical values.
private float mPhysicalCoeff;

Scroller一开始就是一大堆变量,名字可以看出就是一些位置X,Y啊等等,还有滚动的状态,速度值。主要的方法也是getXXX和setXXX,这就是获得属性而已。
关键的两个方法如下:

/**
* Start scrolling by providing a starting point, the distance to travel,
* and the duration of the scroll.
*
* @param startX Starting horizontal scroll offset in pixels. Positive
* numbers will scroll the content to the left.
* @param startY Starting vertical scroll offset in pixels. Positive numbers
* will scroll the content up.
* @param dx Horizontal distance to travel. Positive numbers will scroll the
* content to the left.
* @param dy Vertical distance to travel. Positive numbers will scroll the
* content up.
* @param duration Duration of the scroll in milliseconds.
*/
public void startScroll(int startX, int startY, int dx, int dy, int duration) {
mMode = SCROLL_MODE;
mFinished = false;
mDuration = duration;
mStartTime = AnimationUtils.currentAnimationTimeMillis();
mStartX = startX;
mStartY = startY;
mFinalX = startX + dx;
mFinalY = startY + dy;
mDeltaX = dx;
mDeltaY = dy;
mDurationReciprocal = 1.0f / (float) mDuration;
}

这是通过给定的起始和结束的xy值和时间,计算出对应时间应该对应的坐标。一看都是赋值的语句,都没涉及到View的移动。

另一个是:

/**
* Start scrolling based on a fling gesture. The distance travelled will
* depend on the initial velocity of the fling.
*
* @param startX Starting point of the scroll (X)
* @param startY Starting point of the scroll (Y)
* @param velocityX Initial velocity of the fling (X) measured in pixels per
* second.
* @param velocityY Initial velocity of the fling (Y) measured in pixels per
* second
* @param minX Minimum X value. The scroller will not scroll past this
* point.
* @param maxX Maximum X value. The scroller will not scroll past this
* point.
* @param minY Minimum Y value. The scroller will not scroll past this
* point.
* @param maxY Maximum Y value. The scroller will not scroll past this
* point.
*/
public void fling(int startX, int startY, int velocityX, int velocityY,
int minX, int maxX, int minY, int maxY) {
// Continue a scroll or fling in progress
if (mFlywheel && !mFinished) {
float oldVel = getCurrVelocity();

float dx = (float) (mFinalX - mStartX);
float dy = (float) (mFinalY - mStartY);
float hyp = FloatMath.sqrt(dx * dx + dy * dy);

float ndx = dx / hyp;
float ndy = dy / hyp;

float oldVelocityX = ndx * oldVel;
float oldVelocityY = ndy * oldVel;
if (Math.signum(velocityX) == Math.signum(oldVelocityX) &&
Math.signum(velocityY) == Math.signum(oldVelocityY)) {
velocityX += oldVelocityX;
velocityY += oldVelocityY;
}
}

mMode = FLING_MODE;
mFinished = false;

float velocity = FloatMath.sqrt(velocityX * velocityX + velocityY * velocityY);

mVelocity = velocity;
mDuration = getSplineFlingDuration(velocity);
mStartTime = AnimationUtils.currentAnimationTimeMillis();
mStartX = startX;
mStartY = startY;

float coeffX = velocity == 0 ? 1.0f : velocityX / velocity;
float coeffY = velocity == 0 ? 1.0f : velocityY / velocity;

double totalDistance = getSplineFlingDistance(velocity);
mDistance = (int) (totalDistance * Math.signum(velocity));

mMinX = minX;
mMaxX = maxX;
mMinY = minY;
mMaxY = maxY;

mFinalX = startX + (int) Math.round(totalDistance * coeffX);
// Pin to mMinX <= mFinalX <= mMaxX
mFinalX = Math.min(mFinalX, mMaxX);
mFinalX = Math.max(mFinalX, mMinX);

mFinalY = startY + (int) Math.round(totalDistance * coeffY);
// Pin to mMinY <= mFinalY <= mMaxY
mFinalY = Math.min(mFinalY, mMaxY);
mFinalY = Math.max(mFinalY, mMinY);
}

fling,这个可怕的家伙又来了,其实也没什么,手指放开那一刻,由于View的滚动还有速度,所以这是根据速度来计算接下来的View的位置。

那么,这个Scroller都没有移动Veiw,还要它做什么呢?它就是辅助移动的,我们可以随时通过getCurrX和getCurrY获得View的位置,然后。。。使用ScrollTo来滚动这个Veiw.但是要注意的是,ScrollTo是针对View里面的内容的,如果是是LinearLayout.ScrollTo(),LinearLayout里面的东西全部移动,那如果是TextView.ScrollTo()呢,只是TextView里面的内容移动而已啦~,TextView还是原地不动的。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: