diff options
| author | The Android Open Source Project <initial-contribution@android.com> | 2009-03-03 18:28:45 -0800 |
|---|---|---|
| committer | The Android Open Source Project <initial-contribution@android.com> | 2009-03-03 18:28:45 -0800 |
| commit | d83a98f4ce9cfa908f5c54bbd70f03eec07e7553 (patch) | |
| tree | 4b825dc642cb6eb9a060e54bf8d69288fbee4904 /core/java/android/widget/FastScroller.java | |
| parent | 076357b8567458d4b6dfdcf839ef751634cd2bfb (diff) | |
auto import from //depot/cupcake/@135843
Diffstat (limited to 'core/java/android/widget/FastScroller.java')
| -rw-r--r-- | core/java/android/widget/FastScroller.java | 482 |
1 files changed, 0 insertions, 482 deletions
diff --git a/core/java/android/widget/FastScroller.java b/core/java/android/widget/FastScroller.java deleted file mode 100644 index 57e21e4f7a41..000000000000 --- a/core/java/android/widget/FastScroller.java +++ /dev/null @@ -1,482 +0,0 @@ -/* - * Copyright (C) 2008 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package android.widget; - -import android.content.Context; -import android.content.res.ColorStateList; -import android.content.res.Resources; -import android.content.res.TypedArray; -import android.graphics.Canvas; -import android.graphics.Paint; -import android.graphics.RectF; -import android.graphics.drawable.Drawable; -import android.os.Handler; -import android.os.SystemClock; -import android.util.TypedValue; -import android.view.MotionEvent; - -/** - * Helper class for AbsListView to draw and control the Fast Scroll thumb - */ -class FastScroller { - - // Minimum number of pages to justify showing a fast scroll thumb - private static int MIN_PAGES = 4; - // Scroll thumb not showing - private static final int STATE_NONE = 0; - // Not implemented yet - fade-in transition - private static final int STATE_ENTER = 1; - // Scroll thumb visible and moving along with the scrollbar - private static final int STATE_VISIBLE = 2; - // Scroll thumb being dragged by user - private static final int STATE_DRAGGING = 3; - // Scroll thumb fading out due to inactivity timeout - private static final int STATE_EXIT = 4; - - private Drawable mThumbDrawable; - private Drawable mOverlayDrawable; - - private int mThumbH; - private int mThumbW; - private int mThumbY; - - private RectF mOverlayPos; - private int mOverlaySize = 104; - - private AbsListView mList; - private boolean mScrollCompleted; - private int mVisibleItem; - private Paint mPaint; - private int mListOffset; - - private Object [] mSections; - private String mSectionText; - private boolean mDrawOverlay; - private ScrollFade mScrollFade; - - private int mState; - - private Handler mHandler = new Handler(); - - private BaseAdapter mListAdapter; - private SectionIndexer mSectionIndexer; - - private boolean mChangedBounds; - - public FastScroller(Context context, AbsListView listView) { - mList = listView; - init(context); - } - - public void setState(int state) { - switch (state) { - case STATE_NONE: - mHandler.removeCallbacks(mScrollFade); - mList.invalidate(); - break; - case STATE_VISIBLE: - if (mState != STATE_VISIBLE) { // Optimization - resetThumbPos(); - } - // Fall through - case STATE_DRAGGING: - mHandler.removeCallbacks(mScrollFade); - break; - case STATE_EXIT: - int viewWidth = mList.getWidth(); - mList.invalidate(viewWidth - mThumbW, mThumbY, viewWidth, mThumbY + mThumbH); - break; - } - mState = state; - } - - public int getState() { - return mState; - } - - private void resetThumbPos() { - final int viewWidth = mList.getWidth(); - // Bounds are always top right. Y coordinate get's translated during draw - mThumbDrawable.setBounds(viewWidth - mThumbW, 0, viewWidth, mThumbH); - mThumbDrawable.setAlpha(ScrollFade.ALPHA_MAX); - } - - private void useThumbDrawable(Drawable drawable) { - mThumbDrawable = drawable; - mThumbW = 64; //mCurrentThumb.getIntrinsicWidth(); - mThumbH = 52; //mCurrentThumb.getIntrinsicHeight(); - mChangedBounds = true; - } - - private void init(Context context) { - // Get both the scrollbar states drawables - final Resources res = context.getResources(); - useThumbDrawable(res.getDrawable( - com.android.internal.R.drawable.scrollbar_handle_accelerated_anim2)); - - mOverlayDrawable = res.getDrawable( - com.android.internal.R.drawable.menu_submenu_background); - - mScrollCompleted = true; - - getSections(); - - mOverlayPos = new RectF(); - mScrollFade = new ScrollFade(); - mPaint = new Paint(); - mPaint.setAntiAlias(true); - mPaint.setTextAlign(Paint.Align.CENTER); - mPaint.setTextSize(mOverlaySize / 2); - TypedArray ta = context.getTheme().obtainStyledAttributes(new int[] { - android.R.attr.textColorPrimary }); - ColorStateList textColor = ta.getColorStateList(ta.getIndex(0)); - int textColorNormal = textColor.getDefaultColor(); - mPaint.setColor(textColorNormal); - mPaint.setStyle(Paint.Style.FILL_AND_STROKE); - - mState = STATE_NONE; - } - - void stop() { - setState(STATE_NONE); - } - - boolean isVisible() { - return !(mState == STATE_NONE); - } - - public void draw(Canvas canvas) { - - if (mState == STATE_NONE) { - // No need to draw anything - return; - } - - final int y = mThumbY; - final int viewWidth = mList.getWidth(); - final FastScroller.ScrollFade scrollFade = mScrollFade; - - int alpha = -1; - if (mState == STATE_EXIT) { - alpha = scrollFade.getAlpha(); - if (alpha < ScrollFade.ALPHA_MAX / 2) { - mThumbDrawable.setAlpha(alpha * 2); - } - int left = viewWidth - (mThumbW * alpha) / ScrollFade.ALPHA_MAX; - mThumbDrawable.setBounds(left, 0, viewWidth, mThumbH); - mChangedBounds = true; - } - - canvas.translate(0, y); - mThumbDrawable.draw(canvas); - canvas.translate(0, -y); - - // If user is dragging the scroll bar, draw the alphabet overlay - if (mState == STATE_DRAGGING && mDrawOverlay) { - mOverlayDrawable.draw(canvas); - final Paint paint = mPaint; - float descent = paint.descent(); - final RectF rectF = mOverlayPos; - canvas.drawText(mSectionText, (int) (rectF.left + rectF.right) / 2, - (int) (rectF.bottom + rectF.top) / 2 + mOverlaySize / 4 - descent, paint); - } else if (mState == STATE_EXIT) { - if (alpha == 0) { // Done with exit - setState(STATE_NONE); - } else { - mList.invalidate(viewWidth - mThumbW, y, viewWidth, y + mThumbH); - } - } - } - - void onSizeChanged(int w, int h, int oldw, int oldh) { - if (mThumbDrawable != null) { - mThumbDrawable.setBounds(w - mThumbW, 0, w, mThumbH); - } - final RectF pos = mOverlayPos; - pos.left = (w - mOverlaySize) / 2; - pos.right = pos.left + mOverlaySize; - pos.top = h / 10; // 10% from top - pos.bottom = pos.top + mOverlaySize; - if (mOverlayDrawable != null) { - mOverlayDrawable.setBounds((int) pos.left, (int) pos.top, - (int) pos.right, (int) pos.bottom); - } - } - - void onScroll(AbsListView view, int firstVisibleItem, int visibleItemCount, - int totalItemCount) { - // Are there enough pages to require fast scroll? - if (visibleItemCount > 0 && totalItemCount / visibleItemCount < MIN_PAGES) { - if (mState != STATE_NONE) { - setState(STATE_NONE); - } - return; - } - if (totalItemCount - visibleItemCount > 0 && mState != STATE_DRAGGING ) { - mThumbY = ((mList.getHeight() - mThumbH) * firstVisibleItem) - / (totalItemCount - visibleItemCount); - if (mChangedBounds) { - resetThumbPos(); - mChangedBounds = false; - } - } - mScrollCompleted = true; - if (firstVisibleItem == mVisibleItem) { - return; - } - mVisibleItem = firstVisibleItem; - if (mState != STATE_DRAGGING) { - setState(STATE_VISIBLE); - mHandler.postDelayed(mScrollFade, 1500); - } - } - - private void getSections() { - Adapter adapter = mList.getAdapter(); - mSectionIndexer = null; - if (adapter instanceof HeaderViewListAdapter) { - mListOffset = ((HeaderViewListAdapter)adapter).getHeadersCount(); - adapter = ((HeaderViewListAdapter)adapter).getWrappedAdapter(); - } - if (adapter instanceof ExpandableListConnector) { - ExpandableListAdapter expAdapter = ((ExpandableListConnector)adapter).getAdapter(); - if (expAdapter instanceof SectionIndexer) { - mSectionIndexer = (SectionIndexer) expAdapter; - mListAdapter = (BaseAdapter) adapter; - mSections = mSectionIndexer.getSections(); - } - } else { - if (adapter instanceof SectionIndexer) { - mListAdapter = (BaseAdapter) adapter; - mSectionIndexer = (SectionIndexer) adapter; - mSections = mSectionIndexer.getSections(); - - } else { - mListAdapter = (BaseAdapter) adapter; - mSections = new String[] { " " }; - } - } - } - - private void scrollTo(float position) { - int count = mList.getCount(); - mScrollCompleted = false; - float fThreshold = (1.0f / count) / 8; - final Object[] sections = mSections; - int sectionIndex; - if (sections != null && sections.length > 1) { - final int nSections = sections.length; - int section = (int) (position * nSections); - if (section >= nSections) { - section = nSections - 1; - } - int exactSection = section; - sectionIndex = section; - int index = mSectionIndexer.getPositionForSection(section); - // Given the expected section and index, the following code will - // try to account for missing sections (no names starting with..) - // It will compute the scroll space of surrounding empty sections - // and interpolate the currently visible letter's range across the - // available space, so that there is always some list movement while - // the user moves the thumb. - int nextIndex = count; - int prevIndex = index; - int prevSection = section; - int nextSection = section + 1; - // Assume the next section is unique - if (section < nSections - 1) { - nextIndex = mSectionIndexer.getPositionForSection(section + 1); - } - - // Find the previous index if we're slicing the previous section - if (nextIndex == index) { - // Non-existent letter - while (section > 0) { - section--; - prevIndex = mSectionIndexer.getPositionForSection(section); - if (prevIndex != index) { - prevSection = section; - sectionIndex = section; - break; - } - } - } - // Find the next index, in case the assumed next index is not - // unique. For instance, if there is no P, then request for P's - // position actually returns Q's. So we need to look ahead to make - // sure that there is really a Q at Q's position. If not, move - // further down... - int nextNextSection = nextSection + 1; - while (nextNextSection < nSections && - mSectionIndexer.getPositionForSection(nextNextSection) == nextIndex) { - nextNextSection++; - nextSection++; - } - // Compute the beginning and ending scroll range percentage of the - // currently visible letter. This could be equal to or greater than - // (1 / nSections). - float fPrev = (float) prevSection / nSections; - float fNext = (float) nextSection / nSections; - if (prevSection == exactSection && position - fPrev < fThreshold) { - index = prevIndex; - } else { - index = prevIndex + (int) ((nextIndex - prevIndex) * (position - fPrev) - / (fNext - fPrev)); - } - // Don't overflow - if (index > count - 1) index = count - 1; - - if (mList instanceof ExpandableListView) { - ExpandableListView expList = (ExpandableListView) mList; - expList.setSelectionFromTop(expList.getFlatListPosition( - ExpandableListView.getPackedPositionForGroup(index + mListOffset)), 0); - } else if (mList instanceof ListView) { - ((ListView)mList).setSelectionFromTop(index + mListOffset, 0); - } else { - mList.setSelection(index + mListOffset); - } - } else { - int index = (int) (position * count); - if (mList instanceof ExpandableListView) { - ExpandableListView expList = (ExpandableListView) mList; - expList.setSelectionFromTop(expList.getFlatListPosition( - ExpandableListView.getPackedPositionForGroup(index + mListOffset)), 0); - } else if (mList instanceof ListView) { - ((ListView)mList).setSelectionFromTop(index + mListOffset, 0); - } else { - mList.setSelection(index + mListOffset); - } - sectionIndex = -1; - } - - if (sectionIndex >= 0) { - String text = mSectionText = sections[sectionIndex].toString(); - mDrawOverlay = (text.length() != 1 || text.charAt(0) != ' ') && - sectionIndex < sections.length; - } else { - mDrawOverlay = false; - } - } - - private void cancelFling() { - // Cancel the list fling - MotionEvent cancelFling = MotionEvent.obtain(0, 0, MotionEvent.ACTION_CANCEL, 0, 0, 0); - mList.onTouchEvent(cancelFling); - cancelFling.recycle(); - } - - boolean onInterceptTouchEvent(MotionEvent ev) { - if (mState > STATE_NONE && ev.getAction() == MotionEvent.ACTION_DOWN) { - if (ev.getX() > mList.getWidth() - mThumbW && ev.getY() >= mThumbY && - ev.getY() <= mThumbY + mThumbH) { - setState(STATE_DRAGGING); - return true; - } - } - return false; - } - - boolean onTouchEvent(MotionEvent me) { - if (mState == STATE_NONE) { - return false; - } - if (me.getAction() == MotionEvent.ACTION_DOWN) { - if (me.getX() > mList.getWidth() - mThumbW - && me.getY() >= mThumbY - && me.getY() <= mThumbY + mThumbH) { - - setState(STATE_DRAGGING); - if (mListAdapter == null && mList != null) { - getSections(); - } - - cancelFling(); - return true; - } - } else if (me.getAction() == MotionEvent.ACTION_UP) { - if (mState == STATE_DRAGGING) { - setState(STATE_VISIBLE); - final Handler handler = mHandler; - handler.removeCallbacks(mScrollFade); - handler.postDelayed(mScrollFade, 1000); - return true; - } - } else if (me.getAction() == MotionEvent.ACTION_MOVE) { - if (mState == STATE_DRAGGING) { - final int viewHeight = mList.getHeight(); - // Jitter - int newThumbY = (int) me.getY() - mThumbH + 10; - if (newThumbY < 0) { - newThumbY = 0; - } else if (newThumbY + mThumbH > viewHeight) { - newThumbY = viewHeight - mThumbH; - } - if (Math.abs(mThumbY - newThumbY) < 2) { - return true; - } - mThumbY = newThumbY; - // If the previous scrollTo is still pending - if (mScrollCompleted) { - scrollTo((float) mThumbY / (viewHeight - mThumbH)); - } - return true; - } - } - return false; - } - - public class ScrollFade implements Runnable { - - long mStartTime; - long mFadeDuration; - static final int ALPHA_MAX = 208; - static final long FADE_DURATION = 200; - - void startFade() { - mFadeDuration = FADE_DURATION; - mStartTime = SystemClock.uptimeMillis(); - setState(STATE_EXIT); - } - - int getAlpha() { - if (getState() != STATE_EXIT) { - return ALPHA_MAX; - } - int alpha; - long now = SystemClock.uptimeMillis(); - if (now > mStartTime + mFadeDuration) { - alpha = 0; - } else { - alpha = (int) (ALPHA_MAX - ((now - mStartTime) * ALPHA_MAX) / mFadeDuration); - } - return alpha; - } - - public void run() { - if (getState() != STATE_EXIT) { - startFade(); - return; - } - - if (getAlpha() > 0) { - mList.invalidate(); - } else { - setState(STATE_NONE); - } - } - } -} |
