diff options
author | Adam Powell <adamp@google.com> | 2010-12-08 21:08:53 -0800 |
---|---|---|
committer | Adam Powell <adamp@google.com> | 2010-12-09 22:47:20 -0800 |
commit | 20232d0f7ce2220df72dd78bed052f6b4a643f10 (patch) | |
tree | 26e346a0919a0b16c7a422435e07145c86ab88a9 /core/java/android/widget/FastScroller.java | |
parent | 337885be6e0eadda2d54977104c5738b03f6fb34 (diff) | |
download | frameworks_base-20232d0f7ce2220df72dd78bed052f6b4a643f10.zip frameworks_base-20232d0f7ce2220df72dd78bed052f6b4a643f10.tar.gz frameworks_base-20232d0f7ce2220df72dd78bed052f6b4a643f10.tar.bz2 |
Holo scrollbars and related tweaks.
Added setting for placing vertical scrollbars on left or right.
Added setting for showing fast scroll persistently.
Fixed a bug where inset padding was miscalculated for horizontal scroll bars.
Fixed a bug where padded ListViews would draw fading edges incorrectly
Change-Id: I1f8499895272d42598b4b3fd3375301115def461
Diffstat (limited to 'core/java/android/widget/FastScroller.java')
-rw-r--r-- | core/java/android/widget/FastScroller.java | 242 |
1 files changed, 213 insertions, 29 deletions
diff --git a/core/java/android/widget/FastScroller.java b/core/java/android/widget/FastScroller.java index aa68a74..f824ff4 100644 --- a/core/java/android/widget/FastScroller.java +++ b/core/java/android/widget/FastScroller.java @@ -22,12 +22,14 @@ import android.content.res.Resources; import android.content.res.TypedArray; import android.graphics.Canvas; import android.graphics.Paint; +import android.graphics.Rect; import android.graphics.RectF; import android.graphics.drawable.Drawable; +import android.graphics.drawable.NinePatchDrawable; import android.os.Handler; import android.os.SystemClock; -import android.util.TypedValue; import android.view.MotionEvent; +import android.view.View; import android.widget.AbsListView.OnScrollListener; /** @@ -47,9 +49,38 @@ class FastScroller { private static final int STATE_DRAGGING = 3; // Scroll thumb fading out due to inactivity timeout private static final int STATE_EXIT = 4; + + private static final int[] PRESSED_STATES = new int[] { + android.R.attr.state_pressed + }; + + private static final int[] DEFAULT_STATES = new int[0]; + + private static final int[] ATTRS = new int[] { + android.R.attr.textColorPrimary, + com.android.internal.R.attr.fastScrollThumbDrawable, + com.android.internal.R.attr.fastScrollTrackDrawable, + com.android.internal.R.attr.fastScrollPreviewBackgroundLeft, + com.android.internal.R.attr.fastScrollPreviewBackgroundRight, + com.android.internal.R.attr.fastScrollOverlayPosition + }; + + private static final int PRIMARY_TEXT_COLOR = 0; + private static final int THUMB_DRAWABLE = 1; + private static final int TRACK_DRAWABLE = 2; + private static final int PREVIEW_BACKGROUND_LEFT = 3; + private static final int PREVIEW_BACKGROUND_RIGHT = 4; + private static final int OVERLAY_POSITION = 5; + + private static final int OVERLAY_FLOATING = 0; + private static final int OVERLAY_AT_THUMB = 1; private Drawable mThumbDrawable; private Drawable mOverlayDrawable; + private Drawable mTrackDrawable; + + private Drawable mOverlayDrawableLeft; + private Drawable mOverlayDrawableRight; private int mThumbH; private int mThumbW; @@ -80,11 +111,64 @@ class FastScroller { private boolean mChangedBounds; + private int mPosition; + + private boolean mAlwaysShow; + + private int mOverlayPosition; + + private static final int FADE_TIMEOUT = 1500; + + private final Rect mTmpRect = new Rect(); + public FastScroller(Context context, AbsListView listView) { mList = listView; init(context); } + public void setAlwaysShow(boolean alwaysShow) { + mAlwaysShow = alwaysShow; + if (alwaysShow) { + mHandler.removeCallbacks(mScrollFade); + setState(STATE_VISIBLE); + } else if (mState == STATE_VISIBLE) { + mHandler.postDelayed(mScrollFade, FADE_TIMEOUT); + } + } + + public boolean isAlwaysShowEnabled() { + return mAlwaysShow; + } + + private void refreshDrawableState() { + int[] state = mState == STATE_DRAGGING ? PRESSED_STATES : DEFAULT_STATES; + + if (mThumbDrawable != null && mThumbDrawable.isStateful()) { + mThumbDrawable.setState(state); + } + if (mTrackDrawable != null && mTrackDrawable.isStateful()) { + mTrackDrawable.setState(state); + } + } + + public void setScrollbarPosition(int position) { + mPosition = position; + switch (position) { + default: + case View.SCROLLBAR_POSITION_DEFAULT: + case View.SCROLLBAR_POSITION_RIGHT: + mOverlayDrawable = mOverlayDrawableRight; + break; + case View.SCROLLBAR_POSITION_LEFT: + mOverlayDrawable = mOverlayDrawableLeft; + break; + } + } + + public int getWidth() { + return mThumbW; + } + public void setState(int state) { switch (state) { case STATE_NONE: @@ -105,6 +189,7 @@ class FastScroller { break; } mState = state; + refreshDrawableState(); } public int getState() { @@ -114,27 +199,42 @@ class FastScroller { 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); + switch (mPosition) { + case View.SCROLLBAR_POSITION_DEFAULT: + case View.SCROLLBAR_POSITION_RIGHT: + mThumbDrawable.setBounds(viewWidth - mThumbW, 0, viewWidth, mThumbH); + break; + case View.SCROLLBAR_POSITION_LEFT: + mThumbDrawable.setBounds(0, 0, mThumbW, mThumbH); + break; + } mThumbDrawable.setAlpha(ScrollFade.ALPHA_MAX); } private void useThumbDrawable(Context context, Drawable drawable) { mThumbDrawable = drawable; - mThumbW = context.getResources().getDimensionPixelSize( - com.android.internal.R.dimen.fastscroll_thumb_width); - mThumbH = context.getResources().getDimensionPixelSize( - com.android.internal.R.dimen.fastscroll_thumb_height); + if (drawable instanceof NinePatchDrawable) { + mThumbW = context.getResources().getDimensionPixelSize( + com.android.internal.R.dimen.fastscroll_thumb_width); + mThumbH = context.getResources().getDimensionPixelSize( + com.android.internal.R.dimen.fastscroll_thumb_height); + } else { + mThumbW = drawable.getIntrinsicWidth(); + mThumbH = drawable.getIntrinsicHeight(); + } mChangedBounds = true; } private void init(Context context) { // Get both the scrollbar states drawables final Resources res = context.getResources(); - useThumbDrawable(context, res.getDrawable( - com.android.internal.R.drawable.scrollbar_handle_accelerated_anim2)); + TypedArray ta = context.getTheme().obtainStyledAttributes(ATTRS); + useThumbDrawable(context, ta.getDrawable(ta.getIndex(THUMB_DRAWABLE))); + mTrackDrawable = ta.getDrawable(ta.getIndex(TRACK_DRAWABLE)); - mOverlayDrawable = res.getDrawable( - com.android.internal.R.drawable.menu_submenu_background); + mOverlayDrawableLeft = ta.getDrawable(ta.getIndex(PREVIEW_BACKGROUND_LEFT)); + mOverlayDrawableRight = ta.getDrawable(ta.getIndex(PREVIEW_BACKGROUND_RIGHT)); + mOverlayPosition = ta.getInt(ta.getIndex(OVERLAY_POSITION), OVERLAY_FLOATING); mScrollCompleted = true; @@ -148,9 +248,8 @@ class FastScroller { 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)); + + ColorStateList textColor = ta.getColorStateList(ta.getIndex(PRIMARY_TEXT_COLOR)); int textColorNormal = textColor.getDefaultColor(); mPaint.setColor(textColorNormal); mPaint.setStyle(Paint.Style.FILL_AND_STROKE); @@ -161,6 +260,11 @@ class FastScroller { } mState = STATE_NONE; + refreshDrawableState(); + + ta.recycle(); + + setScrollbarPosition(mList.getVerticalScrollbarPosition()); } void stop() { @@ -188,23 +292,73 @@ class FastScroller { if (alpha < ScrollFade.ALPHA_MAX / 2) { mThumbDrawable.setAlpha(alpha * 2); } - int left = viewWidth - (mThumbW * alpha) / ScrollFade.ALPHA_MAX; - mThumbDrawable.setBounds(left, 0, viewWidth, mThumbH); + int left = 0; + switch (mPosition) { + case View.SCROLLBAR_POSITION_DEFAULT: + case View.SCROLLBAR_POSITION_RIGHT: + left = viewWidth - (mThumbW * alpha) / ScrollFade.ALPHA_MAX; + break; + case View.SCROLLBAR_POSITION_LEFT: + left = -mThumbW + (mThumbW * alpha) / ScrollFade.ALPHA_MAX; + break; + } + mThumbDrawable.setBounds(left, 0, left + mThumbW, mThumbH); mChangedBounds = true; } + if (mTrackDrawable != null) { + final int left = mThumbDrawable.getBounds().left; + final int trackWidth = mTrackDrawable.getIntrinsicWidth(); + final int trackLeft = (left + mThumbW) / 2 - trackWidth / 2; + mTrackDrawable.setBounds(trackLeft, 0, trackLeft + trackWidth, mList.getHeight()); + mTrackDrawable.draw(canvas); + } + 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) { + if (mOverlayPosition == OVERLAY_AT_THUMB) { + int left = 0; + switch (mPosition) { + default: + case View.SCROLLBAR_POSITION_DEFAULT: + case View.SCROLLBAR_POSITION_RIGHT: + left = Math.max(0, + mThumbDrawable.getBounds().left - mThumbW - mOverlaySize); + break; + case View.SCROLLBAR_POSITION_LEFT: + left = Math.min(mThumbDrawable.getBounds().right + mThumbW, + mList.getWidth() - mOverlaySize); + break; + } + + int top = Math.max(0, + Math.min(y + (mThumbH - mOverlaySize) / 2, mList.getHeight() - mOverlaySize)); + + final RectF pos = mOverlayPos; + pos.left = left; + pos.right = pos.left + mOverlaySize; + pos.top = top; + pos.bottom = pos.top + mOverlaySize; + if (mOverlayDrawable != null) { + mOverlayDrawable.setBounds((int) pos.left, (int) pos.top, + (int) pos.right, (int) pos.bottom); + } + } 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); + final Rect tmpRect = mTmpRect; + mOverlayDrawable.getPadding(tmpRect); + final int hOff = (tmpRect.right - tmpRect.left) / 2; + final int vOff = (tmpRect.bottom - tmpRect.top) / 2; + canvas.drawText(mSectionText, (int) (rectF.left + rectF.right) / 2 - hOff, + (int) (rectF.bottom + rectF.top) / 2 + mOverlaySize / 4 - descent - vOff, + paint); } else if (mState == STATE_EXIT) { if (alpha == 0) { // Done with exit setState(STATE_NONE); @@ -216,16 +370,27 @@ class FastScroller { void onSizeChanged(int w, int h, int oldw, int oldh) { if (mThumbDrawable != null) { - mThumbDrawable.setBounds(w - mThumbW, 0, w, mThumbH); + switch (mPosition) { + default: + case View.SCROLLBAR_POSITION_DEFAULT: + case View.SCROLLBAR_POSITION_RIGHT: + mThumbDrawable.setBounds(w - mThumbW, 0, w, mThumbH); + break; + case View.SCROLLBAR_POSITION_LEFT: + mThumbDrawable.setBounds(0, 0, mThumbW, mThumbH); + break; + } } - 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); + if (mOverlayPosition == OVERLAY_FLOATING) { + 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); + } } } @@ -257,7 +422,9 @@ class FastScroller { mVisibleItem = firstVisibleItem; if (mState != STATE_DRAGGING) { setState(STATE_VISIBLE); - mHandler.postDelayed(mScrollFade, 1500); + if (!mAlwaysShow) { + mHandler.postDelayed(mScrollFade, FADE_TIMEOUT); + } } } @@ -454,7 +621,11 @@ class FastScroller { setState(STATE_VISIBLE); final Handler handler = mHandler; handler.removeCallbacks(mScrollFade); - handler.postDelayed(mScrollFade, 1000); + if (!mAlwaysShow) { + handler.postDelayed(mScrollFade, 1000); + } + + mList.invalidate(); return true; } } else if (action == MotionEvent.ACTION_MOVE) { @@ -482,7 +653,20 @@ class FastScroller { } boolean isPointInside(float x, float y) { - return x > mList.getWidth() - mThumbW && y >= mThumbY && y <= mThumbY + mThumbH; + boolean inTrack = false; + switch (mPosition) { + default: + case View.SCROLLBAR_POSITION_DEFAULT: + case View.SCROLLBAR_POSITION_RIGHT: + inTrack = x > mList.getWidth() - mThumbW; + break; + case View.SCROLLBAR_POSITION_LEFT: + inTrack = x < mThumbW; + break; + } + + // Allow taps in the track to start moving. + return inTrack && (mTrackDrawable != null || y >= mThumbY && y <= mThumbY + mThumbH); } public class ScrollFade implements Runnable { |