Android Scroller类介绍

资料:http://blog.csdn.net/gemmem/article/details/7321910

Scroller源码:

  1 /*

  2  * Copyright (C) 2006 The Android Open Source Project

  3  *

  4  * Licensed under the Apache License, Version 2.0 (the "License");

  5  * you may not use this file except in compliance with the License.

  6  * You may obtain a copy of the License at

  7  *

  8  *      http://www.apache.org/licenses/LICENSE-2.0

  9  *

 10  * Unless required by applicable law or agreed to in writing, software

 11  * distributed under the License is distributed on an "AS IS" BASIS,

 12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

 13  * See the License for the specific language governing permissions and

 14  * limitations under the License.

 15  */

 16 

 17 package android.widget;

 18 

 19 import android.content.Context;

 20 import android.hardware.SensorManager;

 21 import android.os.Build;

 22 import android.util.FloatMath;

 23 import android.view.ViewConfiguration;

 24 import android.view.animation.AnimationUtils;

 25 import android.view.animation.Interpolator;

 26 

 27 

 28 /**

 29  * This class encapsulates scrolling.  The duration of the scroll

 30  * can be passed in the constructor and specifies the maximum time that

 31  * the scrolling animation should take.  Past this time, the scrolling is 

 32  * automatically moved to its final stage and computeScrollOffset()

 33  * will always return false to indicate that scrolling is over.

 34  */

 35 public class Scroller  {

 36     private int mMode;

 37 

 38     private int mStartX;

 39     private int mStartY;

 40     private int mFinalX;

 41     private int mFinalY;

 42 

 43     private int mMinX;

 44     private int mMaxX;

 45     private int mMinY;

 46     private int mMaxY;

 47 

 48     private int mCurrX;

 49     private int mCurrY;

 50     private long mStartTime;

 51     private int mDuration;

 52     private float mDurationReciprocal;

 53     private float mDeltaX;

 54     private float mDeltaY;

 55     private boolean mFinished;

 56     private Interpolator mInterpolator;

 57     private boolean mFlywheel;

 58 

 59     private float mVelocity;

 60 

 61     private static final int DEFAULT_DURATION = 250;

 62     private static final int SCROLL_MODE = 0;

 63     private static final int FLING_MODE = 1;

 64 

 65     private static float DECELERATION_RATE = (float) (Math.log(0.75) / Math.log(0.9));

 66     private static float ALPHA = 800; // pixels / seconds

 67     private static float START_TENSION = 0.4f; // Tension at start: (0.4 * total T, 1.0 * Distance)

 68     private static float END_TENSION = 1.0f - START_TENSION;

 69     private static final int NB_SAMPLES = 100;

 70     private static final float[] SPLINE = new float[NB_SAMPLES + 1];

 71 

 72     private float mDeceleration;

 73     private final float mPpi;

 74 

 75     static {

 76         float x_min = 0.0f;

 77         for (int i = 0; i <= NB_SAMPLES; i++) {

 78             final float t = (float) i / NB_SAMPLES;

 79             float x_max = 1.0f;

 80             float x, tx, coef;

 81             while (true) {

 82                 x = x_min + (x_max - x_min) / 2.0f;

 83                 coef = 3.0f * x * (1.0f - x);

 84                 tx = coef * ((1.0f - x) * START_TENSION + x * END_TENSION) + x * x * x;

 85                 if (Math.abs(tx - t) < 1E-5) break;

 86                 if (tx > t) x_max = x;

 87                 else x_min = x;

 88             }

 89             final float d = coef + x * x * x;

 90             SPLINE[i] = d;

 91         }

 92         SPLINE[NB_SAMPLES] = 1.0f;

 93 

 94         // This controls the viscous fluid effect (how much of it)

 95         sViscousFluidScale = 8.0f;

 96         // must be set to 1.0 (used in viscousFluid())

 97         sViscousFluidNormalize = 1.0f;

 98         sViscousFluidNormalize = 1.0f / viscousFluid(1.0f);

 99     }

100 

101     private static float sViscousFluidScale;

102     private static float sViscousFluidNormalize;

103 

104     /**

105      * Create a Scroller with the default duration and interpolator.

106      */

107     public Scroller(Context context) {

108         this(context, null);

109     }

110 

111     /**

112      * Create a Scroller with the specified interpolator. If the interpolator is

113      * null, the default (viscous) interpolator will be used. "Flywheel" behavior will

114      * be in effect for apps targeting Honeycomb or newer.

115      */

116     public Scroller(Context context, Interpolator interpolator) {

117         this(context, interpolator,

118                 context.getApplicationInfo().targetSdkVersion >= Build.VERSION_CODES.HONEYCOMB);

119     }

120 

121     /**

122      * Create a Scroller with the specified interpolator. If the interpolator is

123      * null, the default (viscous) interpolator will be used. Specify whether or

124      * not to support progressive "flywheel" behavior in flinging.

125      */

126     public Scroller(Context context, Interpolator interpolator, boolean flywheel) {

127         mFinished = true;

128         mInterpolator = interpolator;

129         mPpi = context.getResources().getDisplayMetrics().density * 160.0f;

130         mDeceleration = computeDeceleration(ViewConfiguration.getScrollFriction());

131         mFlywheel = flywheel;

132     }

133 

134     /**

135      * The amount of friction applied to flings. The default value

136      * is {@link ViewConfiguration#getScrollFriction}.

137      * 

138      * @param friction A scalar dimension-less value representing the coefficient of

139      *         friction.

140      */

141     public final void setFriction(float friction) {

142         mDeceleration = computeDeceleration(friction);

143     }

144     

145     private float computeDeceleration(float friction) {

146         return SensorManager.GRAVITY_EARTH   // g (m/s^2)

147                       * 39.37f               // inch/meter

148                       * mPpi                 // pixels per inch

149                       * friction;

150     }

151 

152     /**

153      * 

154      * Returns whether the scroller has finished scrolling.

155      * 

156      * @return True if the scroller has finished scrolling, false otherwise.

157      */

158     public final boolean isFinished() {

159         return mFinished;

160     }

161     

162     /**

163      * Force the finished field to a particular value.

164      *  

165      * @param finished The new finished value.

166      */

167     public final void forceFinished(boolean finished) {

168         mFinished = finished;

169     }

170     

171     /**

172      * Returns how long the scroll event will take, in milliseconds.

173      * 

174      * @return The duration of the scroll in milliseconds.

175      */

176     public final int getDuration() {

177         return mDuration;

178     }

179     

180     /**

181      * Returns the current X offset in the scroll. 

182      * 

183      * @return The new X offset as an absolute distance from the origin.

184      */

185     public final int getCurrX() {

186         return mCurrX;

187     }

188     

189     /**

190      * Returns the current Y offset in the scroll. 

191      * 

192      * @return The new Y offset as an absolute distance from the origin.

193      */

194     public final int getCurrY() {

195         return mCurrY;

196     }

197     

198     /**

199      * Returns the current velocity.

200      *

201      * @return The original velocity less the deceleration. Result may be

202      * negative.

203      */

204     public float getCurrVelocity() {

205         return mVelocity - mDeceleration * timePassed() / 2000.0f;

206     }

207 

208     /**

209      * Returns the start X offset in the scroll. 

210      * 

211      * @return The start X offset as an absolute distance from the origin.

212      */

213     public final int getStartX() {

214         return mStartX;

215     }

216     

217     /**

218      * Returns the start Y offset in the scroll. 

219      * 

220      * @return The start Y offset as an absolute distance from the origin.

221      */

222     public final int getStartY() {

223         return mStartY;

224     }

225     

226     /**

227      * Returns where the scroll will end. Valid only for "fling" scrolls.

228      * 

229      * @return The final X offset as an absolute distance from the origin.

230      */

231     public final int getFinalX() {

232         return mFinalX;

233     }

234     

235     /**

236      * Returns where the scroll will end. Valid only for "fling" scrolls.

237      * 

238      * @return The final Y offset as an absolute distance from the origin.

239      */

240     public final int getFinalY() {

241         return mFinalY;

242     }

243 

244     /**

245      * Call this when you want to know the new location.  If it returns true,

246      * the animation is not yet finished.  loc will be altered to provide the

247      * new location.

248      */ 

249     public boolean computeScrollOffset() {

250         if (mFinished) {

251             return false;

252         }

253 

254         int timePassed = (int)(AnimationUtils.currentAnimationTimeMillis() - mStartTime);

255     

256         if (timePassed < mDuration) {

257             switch (mMode) {

258             case SCROLL_MODE:

259                 float x = timePassed * mDurationReciprocal;

260     

261                 if (mInterpolator == null)

262                     x = viscousFluid(x); 

263                 else

264                     x = mInterpolator.getInterpolation(x);

265     

266                 mCurrX = mStartX + Math.round(x * mDeltaX);

267                 mCurrY = mStartY + Math.round(x * mDeltaY);

268                 break;

269             case FLING_MODE:

270                 final float t = (float) timePassed / mDuration;

271                 final int index = (int) (NB_SAMPLES * t);

272                 final float t_inf = (float) index / NB_SAMPLES;

273                 final float t_sup = (float) (index + 1) / NB_SAMPLES;

274                 final float d_inf = SPLINE[index];

275                 final float d_sup = SPLINE[index + 1];

276                 final float distanceCoef = d_inf + (t - t_inf) / (t_sup - t_inf) * (d_sup - d_inf);

277                 

278                 mCurrX = mStartX + Math.round(distanceCoef * (mFinalX - mStartX));

279                 // Pin to mMinX <= mCurrX <= mMaxX

280                 mCurrX = Math.min(mCurrX, mMaxX);

281                 mCurrX = Math.max(mCurrX, mMinX);

282                 

283                 mCurrY = mStartY + Math.round(distanceCoef * (mFinalY - mStartY));

284                 // Pin to mMinY <= mCurrY <= mMaxY

285                 mCurrY = Math.min(mCurrY, mMaxY);

286                 mCurrY = Math.max(mCurrY, mMinY);

287 

288                 if (mCurrX == mFinalX && mCurrY == mFinalY) {

289                     mFinished = true;

290                 }

291 

292                 break;

293             }

294         }

295         else {

296             mCurrX = mFinalX;

297             mCurrY = mFinalY;

298             mFinished = true;

299         }

300         return true;

301     }

302     

303     /**

304      * Start scrolling by providing a starting point and the distance to travel.

305      * The scroll will use the default value of 250 milliseconds for the

306      * duration.

307      * 

308      * @param startX Starting horizontal scroll offset in pixels. Positive

309      *        numbers will scroll the content to the left.

310      * @param startY Starting vertical scroll offset in pixels. Positive numbers

311      *        will scroll the content up.

312      * @param dx Horizontal distance to travel. Positive numbers will scroll the

313      *        content to the left.

314      * @param dy Vertical distance to travel. Positive numbers will scroll the

315      *        content up.

316      */

317     public void startScroll(int startX, int startY, int dx, int dy) {

318         startScroll(startX, startY, dx, dy, DEFAULT_DURATION);

319     }

320 

321     /**

322      * Start scrolling by providing a starting point and the distance to travel.

323      * 

324      * @param startX Starting horizontal scroll offset in pixels. Positive

325      *        numbers will scroll the content to the left.

326      * @param startY Starting vertical scroll offset in pixels. Positive numbers

327      *        will scroll the content up.

328      * @param dx Horizontal distance to travel. Positive numbers will scroll the

329      *        content to the left.

330      * @param dy Vertical distance to travel. Positive numbers will scroll the

331      *        content up.

332      * @param duration Duration of the scroll in milliseconds.

333      */

334     public void startScroll(int startX, int startY, int dx, int dy, int duration) {

335         mMode = SCROLL_MODE;

336         mFinished = false;

337         mDuration = duration;

338         mStartTime = AnimationUtils.currentAnimationTimeMillis();

339         mStartX = startX;

340         mStartY = startY;

341         mFinalX = startX + dx;

342         mFinalY = startY + dy;

343         mDeltaX = dx;

344         mDeltaY = dy;

345         mDurationReciprocal = 1.0f / (float) mDuration;

346     }

347 

348     /**

349      * Start scrolling based on a fling gesture. The distance travelled will

350      * depend on the initial velocity of the fling.

351      * 

352      * @param startX Starting point of the scroll (X)

353      * @param startY Starting point of the scroll (Y)

354      * @param velocityX Initial velocity of the fling (X) measured in pixels per

355      *        second.

356      * @param velocityY Initial velocity of the fling (Y) measured in pixels per

357      *        second

358      * @param minX Minimum X value. The scroller will not scroll past this

359      *        point.

360      * @param maxX Maximum X value. The scroller will not scroll past this

361      *        point.

362      * @param minY Minimum Y value. The scroller will not scroll past this

363      *        point.

364      * @param maxY Maximum Y value. The scroller will not scroll past this

365      *        point.

366      */

367     public void fling(int startX, int startY, int velocityX, int velocityY,

368             int minX, int maxX, int minY, int maxY) {

369         // Continue a scroll or fling in progress

370         if (mFlywheel && !mFinished) {

371             float oldVel = getCurrVelocity();

372 

373             float dx = (float) (mFinalX - mStartX);

374             float dy = (float) (mFinalY - mStartY);

375             float hyp = FloatMath.sqrt(dx * dx + dy * dy);

376 

377             float ndx = dx / hyp;

378             float ndy = dy / hyp;

379 

380             float oldVelocityX = ndx * oldVel;

381             float oldVelocityY = ndy * oldVel;

382             if (Math.signum(velocityX) == Math.signum(oldVelocityX) &&

383                     Math.signum(velocityY) == Math.signum(oldVelocityY)) {

384                 velocityX += oldVelocityX;

385                 velocityY += oldVelocityY;

386             }

387         }

388 

389         mMode = FLING_MODE;

390         mFinished = false;

391 

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

393      

394         mVelocity = velocity;

395         final double l = Math.log(START_TENSION * velocity / ALPHA);

396         mDuration = (int) (1000.0 * Math.exp(l / (DECELERATION_RATE - 1.0)));

397         mStartTime = AnimationUtils.currentAnimationTimeMillis();

398         mStartX = startX;

399         mStartY = startY;

400 

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

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

403 

404         int totalDistance =

405                 (int) (ALPHA * Math.exp(DECELERATION_RATE / (DECELERATION_RATE - 1.0) * l));

406         

407         mMinX = minX;

408         mMaxX = maxX;

409         mMinY = minY;

410         mMaxY = maxY;

411 

412         mFinalX = startX + Math.round(totalDistance * coeffX);

413         // Pin to mMinX <= mFinalX <= mMaxX

414         mFinalX = Math.min(mFinalX, mMaxX);

415         mFinalX = Math.max(mFinalX, mMinX);

416         

417         mFinalY = startY + Math.round(totalDistance * coeffY);

418         // Pin to mMinY <= mFinalY <= mMaxY

419         mFinalY = Math.min(mFinalY, mMaxY);

420         mFinalY = Math.max(mFinalY, mMinY);

421     }

422     

423     static float viscousFluid(float x)

424     {

425         x *= sViscousFluidScale;

426         if (x < 1.0f) {

427             x -= (1.0f - (float)Math.exp(-x));

428         } else {

429             float start = 0.36787944117f;   // 1/e == exp(-1)

430             x = 1.0f - (float)Math.exp(1.0f - x);

431             x = start + x * (1.0f - start);

432         }

433         x *= sViscousFluidNormalize;

434         return x;

435     }

436     

437     /**

438      * Stops the animation. Contrary to {@link #forceFinished(boolean)},

439      * aborting the animating cause the scroller to move to the final x and y

440      * position

441      *

442      * @see #forceFinished(boolean)

443      */

444     public void abortAnimation() {

445         mCurrX = mFinalX;

446         mCurrY = mFinalY;

447         mFinished = true;

448     }

449     

450     /**

451      * Extend the scroll animation. This allows a running animation to scroll

452      * further and longer, when used with {@link #setFinalX(int)} or {@link #setFinalY(int)}.

453      *

454      * @param extend Additional time to scroll in milliseconds.

455      * @see #setFinalX(int)

456      * @see #setFinalY(int)

457      */

458     public void extendDuration(int extend) {

459         int passed = timePassed();

460         mDuration = passed + extend;

461         mDurationReciprocal = 1.0f / mDuration;

462         mFinished = false;

463     }

464 

465     /**

466      * Returns the time elapsed since the beginning of the scrolling.

467      *

468      * @return The elapsed time in milliseconds.

469      */

470     public int timePassed() {

471         return (int)(AnimationUtils.currentAnimationTimeMillis() - mStartTime);

472     }

473 

474     /**

475      * Sets the final position (X) for this scroller.

476      *

477      * @param newX The new X offset as an absolute distance from the origin.

478      * @see #extendDuration(int)

479      * @see #setFinalY(int)

480      */

481     public void setFinalX(int newX) {

482         mFinalX = newX;

483         mDeltaX = mFinalX - mStartX;

484         mFinished = false;

485     }

486 

487     /**

488      * Sets the final position (Y) for this scroller.

489      *

490      * @param newY The new Y offset as an absolute distance from the origin.

491      * @see #extendDuration(int)

492      * @see #setFinalX(int)

493      */

494     public void setFinalY(int newY) {

495         mFinalY = newY;

496         mDeltaY = mFinalY - mStartY;

497         mFinished = false;

498     }

499 

500     /**

501      * @hide

502      */

503     public boolean isScrollingInDirection(float xvel, float yvel) {

504         return !mFinished && Math.signum(xvel) == Math.signum(mFinalX - mStartX) &&

505                 Math.signum(yvel) == Math.signum(mFinalY - mStartY);

506     }

507 }

Scroller源码只有507行,结合链接中资料发现,Scroller只是一个计算滚动位置的帮助类,用来计算出当前应该滚动到的位置,而且每次获取位置必须调用computeScrollOffset方法才能刷新,Scroller还是很好用的,按照这个思路,以后如果滑动需要特殊计算可以按照Scroller自定义一个计算类。

你可能感兴趣的:(android)