Fading scrollbars return. But you have to opt in.

This commit is contained in:
Mike Cleron
2009-09-27 19:14:12 -07:00
parent 5d062bc3de
commit f116bf8884
12 changed files with 369 additions and 31 deletions

View File

@ -24,6 +24,7 @@ import android.content.res.Resources;
import android.content.res.TypedArray; import android.content.res.TypedArray;
import android.graphics.Bitmap; import android.graphics.Bitmap;
import android.graphics.Canvas; import android.graphics.Canvas;
import android.graphics.Interpolator;
import android.graphics.LinearGradient; import android.graphics.LinearGradient;
import android.graphics.Matrix; import android.graphics.Matrix;
import android.graphics.Paint; import android.graphics.Paint;
@ -514,7 +515,8 @@ import java.util.WeakHashMap;
* The framework provides basic support for views that wish to internally * The framework provides basic support for views that wish to internally
* scroll their content. This includes keeping track of the X and Y scroll * scroll their content. This includes keeping track of the X and Y scroll
* offset as well as mechanisms for drawing scrollbars. See * offset as well as mechanisms for drawing scrollbars. See
* {@link #scrollBy(int, int)}, {@link #scrollTo(int, int)} for more details. * {@link #scrollBy(int, int)}, {@link #scrollTo(int, int)}, and
* {@link #awakenScrollBars()} for more details.
* </p> * </p>
* *
* <a name="Tags"></a> * <a name="Tags"></a>
@ -571,6 +573,8 @@ import java.util.WeakHashMap;
* @attr ref android.R.styleable#View_scrollbarSize * @attr ref android.R.styleable#View_scrollbarSize
* @attr ref android.R.styleable#View_scrollbarStyle * @attr ref android.R.styleable#View_scrollbarStyle
* @attr ref android.R.styleable#View_scrollbars * @attr ref android.R.styleable#View_scrollbars
* @attr ref android.R.styleable#View_scrollbarDefaultDelayBeforeFade
* @attr ref android.R.styleable#View_scrollbarFadeDuration
* @attr ref android.R.styleable#View_scrollbarTrackHorizontal * @attr ref android.R.styleable#View_scrollbarTrackHorizontal
* @attr ref android.R.styleable#View_scrollbarThumbHorizontal * @attr ref android.R.styleable#View_scrollbarThumbHorizontal
* @attr ref android.R.styleable#View_scrollbarThumbVertical * @attr ref android.R.styleable#View_scrollbarThumbVertical
@ -2214,12 +2218,28 @@ public class View implements Drawable.Callback, KeyEvent.Callback, Accessibility
protected void initializeScrollbars(TypedArray a) { protected void initializeScrollbars(TypedArray a) {
initScrollCache(); initScrollCache();
if (mScrollCache.scrollBar == null) {
mScrollCache.scrollBar = new ScrollBarDrawable();
}
final ScrollabilityCache scrollabilityCache = mScrollCache; final ScrollabilityCache scrollabilityCache = mScrollCache;
if (scrollabilityCache.scrollBar == null) {
scrollabilityCache.scrollBar = new ScrollBarDrawable();
}
final boolean fadeScrollbars = a.getBoolean(R.styleable.View_fadeScrollbars, false);
if (!fadeScrollbars) {
scrollabilityCache.state = ScrollabilityCache.ON;
}
scrollabilityCache.fadeScrollBars = fadeScrollbars;
scrollabilityCache.scrollBarFadeDuration = a.getInt(
R.styleable.View_scrollbarFadeDuration, ViewConfiguration
.getScrollBarFadeDuration());
scrollabilityCache.scrollBarDefaultDelayBeforeFade = a.getInt(
R.styleable.View_scrollbarDefaultDelayBeforeFade,
ViewConfiguration.getScrollDefaultDelay());
scrollabilityCache.scrollBarSize = a.getDimensionPixelSize( scrollabilityCache.scrollBarSize = a.getDimensionPixelSize(
com.android.internal.R.styleable.View_scrollbarSize, com.android.internal.R.styleable.View_scrollbarSize,
ViewConfiguration.get(mContext).getScaledScrollBarSize()); ViewConfiguration.get(mContext).getScaledScrollBarSize());
@ -2263,7 +2283,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback, Accessibility
*/ */
private void initScrollCache() { private void initScrollCache() {
if (mScrollCache == null) { if (mScrollCache == null) {
mScrollCache = new ScrollabilityCache(ViewConfiguration.get(mContext)); mScrollCache = new ScrollabilityCache(ViewConfiguration.get(mContext), this);
} }
} }
@ -4671,7 +4691,9 @@ public class View implements Drawable.Callback, KeyEvent.Callback, Accessibility
mScrollX = x; mScrollX = x;
mScrollY = y; mScrollY = y;
onScrollChanged(mScrollX, mScrollY, oldX, oldY); onScrollChanged(mScrollX, mScrollY, oldX, oldY);
invalidate(); if (!awakenScrollBars()) {
invalidate();
}
} }
} }
@ -4686,6 +4708,120 @@ public class View implements Drawable.Callback, KeyEvent.Callback, Accessibility
scrollTo(mScrollX + x, mScrollY + y); scrollTo(mScrollX + x, mScrollY + y);
} }
/**
* <p>Trigger the scrollbars to draw. When invoked this method starts an
* animation to fade the scrollbars out after a default delay. If a subclass
* provides animated scrolling, the start delay should equal the duration
* of the scrolling animation.</p>
*
* <p>The animation starts only if at least one of the scrollbars is
* enabled, as specified by {@link #isHorizontalScrollBarEnabled()} and
* {@link #isVerticalScrollBarEnabled()}. When the animation is started,
* this method returns true, and false otherwise. If the animation is
* started, this method calls {@link #invalidate()}; in that case the
* caller should not call {@link #invalidate()}.</p>
*
* <p>This method should be invoked every time a subclass directly updates
* the scroll parameters. (See {@link #mScrollX} and {@link #mScrollY})</p>
*
* <p>This method is automatically invoked by {@link #scrollBy(int, int)}
* and {@link #scrollTo(int, int)}.</p>
*
* @return true if the animation is played, false otherwise
*
* @see #awakenScrollBars(int)
* @see #mScrollX
* @see #mScrollY
* @see #scrollBy(int, int)
* @see #scrollTo(int, int)
* @see #isHorizontalScrollBarEnabled()
* @see #isVerticalScrollBarEnabled()
* @see #setHorizontalScrollBarEnabled(boolean)
* @see #setVerticalScrollBarEnabled(boolean)
*/
protected boolean awakenScrollBars() {
return mScrollCache != null &&
awakenScrollBars(mScrollCache.scrollBarDefaultDelayBeforeFade);
}
/**
* <p>
* Trigger the scrollbars to draw. When invoked this method starts an
* animation to fade the scrollbars out after a fixed delay. If a subclass
* provides animated scrolling, the start delay should equal the duration of
* the scrolling animation.
* </p>
*
* <p>
* The animation starts only if at least one of the scrollbars is enabled,
* as specified by {@link #isHorizontalScrollBarEnabled()} and
* {@link #isVerticalScrollBarEnabled()}. When the animation is started,
* this method returns true, and false otherwise. If the animation is
* started, this method calls {@link #invalidate()}; in that case the caller
* should not call {@link #invalidate()}.
* </p>
*
* <p>
* This method should be invoked everytime a subclass directly updates the
* scroll parameters. (See {@link #mScrollX} and {@link #mScrollY})
* </p>
*
* @param startDelay the delay, in milliseconds, after which the animation
* should start; when the delay is 0, the animation starts
* immediately
* @return true if the animation is played, false otherwise
*
* @see #mScrollX
* @see #mScrollY
* @see #scrollBy(int, int)
* @see #scrollTo(int, int)
* @see #isHorizontalScrollBarEnabled()
* @see #isVerticalScrollBarEnabled()
* @see #setHorizontalScrollBarEnabled(boolean)
* @see #setVerticalScrollBarEnabled(boolean)
*/
protected boolean awakenScrollBars(int startDelay) {
final ScrollabilityCache scrollCache = mScrollCache;
if (scrollCache == null || !scrollCache.fadeScrollBars) {
return false;
}
if (scrollCache.scrollBar == null) {
scrollCache.scrollBar = new ScrollBarDrawable();
}
if (isHorizontalScrollBarEnabled() || isVerticalScrollBarEnabled()) {
// Invalidate to show the scrollbars
invalidate();
if (scrollCache.state == ScrollabilityCache.OFF) {
// FIXME: this is copied from WindowManagerService.
// We should get this value from the system when it
// is possible to do so.
final int KEY_REPEAT_FIRST_DELAY = 750;
startDelay = Math.max(KEY_REPEAT_FIRST_DELAY, startDelay);
}
// Tell mScrollCache when we should start fading. This may
// extend the fade start time if one was already scheduled
long fadeStartTime = SystemClock.uptimeMillis() + startDelay;
scrollCache.fadeStartTime = fadeStartTime;
scrollCache.state = ScrollabilityCache.ON;
// Schedule our fader to run, unscheduling any old ones first
if (mAttachInfo != null) {
mAttachInfo.mHandler.removeCallbacks(scrollCache);
mAttachInfo.mHandler.postAtTime(scrollCache, fadeStartTime);
}
return true;
}
return false;
}
/** /**
* Mark the the area defined by dirty as needing to be drawn. If the view is * Mark the the area defined by dirty as needing to be drawn. If the view is
* visible, {@link #onDraw} will be called at some point in the future. * visible, {@link #onDraw} will be called at some point in the future.
@ -5344,11 +5480,49 @@ public class View implements Drawable.Callback, KeyEvent.Callback, Accessibility
* scrollbars are painted only if they have been awakened first.</p> * scrollbars are painted only if they have been awakened first.</p>
* *
* @param canvas the canvas on which to draw the scrollbars * @param canvas the canvas on which to draw the scrollbars
*
* @see #awakenScrollBars(int)
*/ */
private void onDrawScrollBars(Canvas canvas) { private void onDrawScrollBars(Canvas canvas) {
// scrollbars are drawn only when the animation is running // scrollbars are drawn only when the animation is running
final ScrollabilityCache cache = mScrollCache; final ScrollabilityCache cache = mScrollCache;
if (cache != null) { if (cache != null) {
int state = cache.state;
if (state == ScrollabilityCache.OFF) {
return;
}
boolean invalidate = false;
if (state == ScrollabilityCache.FADING) {
// We're fading -- get our fade interpolation
if (cache.interpolatorValues == null) {
cache.interpolatorValues = new float[1];
}
float[] values = cache.interpolatorValues;
// Stops the animation if we're done
if (cache.scrollBarInterpolator.timeToValues(values) ==
Interpolator.Result.FREEZE_END) {
cache.state = ScrollabilityCache.OFF;
} else {
cache.scrollBar.setAlpha(Math.round(values[0]));
}
// This will make the scroll bars inval themselves after
// drawing. We only want this when we're fading so that
// we prevent excessive redraws
invalidate = true;
} else {
// We're just on -- but we may have been fading before so
// reset alpha
cache.scrollBar.setAlpha(255);
}
final int viewFlags = mViewFlags; final int viewFlags = mViewFlags;
final boolean drawHorizontalScrollBar = final boolean drawHorizontalScrollBar =
@ -5371,19 +5545,22 @@ public class View implements Drawable.Callback, KeyEvent.Callback, Accessibility
final int scrollY = mScrollY; final int scrollY = mScrollY;
final int inside = (viewFlags & SCROLLBARS_OUTSIDE_MASK) == 0 ? ~0 : 0; final int inside = (viewFlags & SCROLLBARS_OUTSIDE_MASK) == 0 ? ~0 : 0;
int left, top, right, bottom;
if (drawHorizontalScrollBar) { if (drawHorizontalScrollBar) {
scrollBar.setParameters( scrollBar.setParameters(computeHorizontalScrollRange(),
computeHorizontalScrollRange(),
computeHorizontalScrollOffset(), computeHorizontalScrollOffset(),
computeHorizontalScrollExtent(), false); computeHorizontalScrollExtent(), false);
final int top = scrollY + height - size - (mUserPaddingBottom & inside);
final int verticalScrollBarGap = drawVerticalScrollBar ? final int verticalScrollBarGap = drawVerticalScrollBar ?
getVerticalScrollbarWidth() : 0; getVerticalScrollbarWidth() : 0;
onDrawHorizontalScrollBar(canvas, scrollBar, top = scrollY + height - size - (mUserPaddingBottom & inside);
scrollX + (mPaddingLeft & inside), left = scrollX + (mPaddingLeft & inside);
top, right = scrollX + width - (mUserPaddingRight & inside) - verticalScrollBarGap;
scrollX + width - (mUserPaddingRight & inside) - verticalScrollBarGap, bottom = top + size;
top + size); onDrawHorizontalScrollBar(canvas, scrollBar, left, top, right, bottom);
if (invalidate) {
invalidate(left, top, right, bottom);
}
} }
if (drawVerticalScrollBar) { if (drawVerticalScrollBar) {
@ -5391,12 +5568,14 @@ public class View implements Drawable.Callback, KeyEvent.Callback, Accessibility
computeVerticalScrollOffset(), computeVerticalScrollOffset(),
computeVerticalScrollExtent(), true); computeVerticalScrollExtent(), true);
// TODO: Deal with RTL languages to position scrollbar on left // TODO: Deal with RTL languages to position scrollbar on left
final int left = scrollX + width - size - (mUserPaddingRight & inside); left = scrollX + width - size - (mUserPaddingRight & inside);
onDrawVerticalScrollBar(canvas, scrollBar, top = scrollY + (mPaddingTop & inside);
left, right = left + size;
scrollY + (mPaddingTop & inside), bottom = scrollY + height - (mUserPaddingBottom & inside);
left + size, onDrawVerticalScrollBar(canvas, scrollBar, left, top, right, bottom);
scrollY + height - (mUserPaddingBottom & inside)); if (invalidate) {
invalidate(left, top, right, bottom);
}
} }
} }
} }
@ -5424,7 +5603,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback, Accessibility
* @see #computeHorizontalScrollExtent() * @see #computeHorizontalScrollExtent()
* @see #computeHorizontalScrollOffset() * @see #computeHorizontalScrollOffset()
* @see android.widget.ScrollBarDrawable * @see android.widget.ScrollBarDrawable
* @hide * @hide
*/ */
protected void onDrawHorizontalScrollBar(Canvas canvas, protected void onDrawHorizontalScrollBar(Canvas canvas,
Drawable scrollBar, Drawable scrollBar,
@ -8731,21 +8910,62 @@ public class View implements Drawable.Callback, KeyEvent.Callback, Accessibility
* is supported. This avoids keeping too many unused fields in most * is supported. This avoids keeping too many unused fields in most
* instances of View.</p> * instances of View.</p>
*/ */
private static class ScrollabilityCache { private static class ScrollabilityCache implements Runnable {
/**
* Scrollbars are not visible
*/
public static final int OFF = 0;
/**
* Scrollbars are visible
*/
public static final int ON = 1;
/**
* Scrollbars are fading away
*/
public static final int FADING = 2;
public boolean fadeScrollBars;
public int fadingEdgeLength; public int fadingEdgeLength;
public int scrollBarDefaultDelayBeforeFade;
public int scrollBarFadeDuration;
public int scrollBarSize; public int scrollBarSize;
public ScrollBarDrawable scrollBar; public ScrollBarDrawable scrollBar;
public float[] interpolatorValues;
public View host;
public final Paint paint; public final Paint paint;
public final Matrix matrix; public final Matrix matrix;
public Shader shader; public Shader shader;
public final Interpolator scrollBarInterpolator = new Interpolator(1, 2);
private final float[] mOpaque = {255.0f};
private final float[] mTransparent = {0.0f};
/**
* When fading should start. This time moves into the future every time
* a new scroll happens. Measured based on SystemClock.uptimeMillis()
*/
public long fadeStartTime;
/**
* The current state of the scrollbars: ON, OFF, or FADING
*/
public int state = OFF;
private int mLastColor; private int mLastColor;
public ScrollabilityCache(ViewConfiguration configuration) { public ScrollabilityCache(ViewConfiguration configuration, View host) {
fadingEdgeLength = configuration.getScaledFadingEdgeLength(); fadingEdgeLength = configuration.getScaledFadingEdgeLength();
scrollBarSize = configuration.getScaledScrollBarSize(); scrollBarSize = configuration.getScaledScrollBarSize();
scrollBarDefaultDelayBeforeFade = configuration.getScrollDefaultDelay();
scrollBarFadeDuration = configuration.getScrollBarFadeDuration();
paint = new Paint(); paint = new Paint();
matrix = new Matrix(); matrix = new Matrix();
@ -8755,6 +8975,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback, Accessibility
paint.setShader(shader); paint.setShader(shader);
paint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.DST_OUT)); paint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.DST_OUT));
this.host = host;
} }
public void setFadeColor(int color) { public void setFadeColor(int color) {
@ -8770,5 +8991,32 @@ public class View implements Drawable.Callback, KeyEvent.Callback, Accessibility
paint.setXfermode(null); paint.setXfermode(null);
} }
} }
public void run() {
long now = SystemClock.uptimeMillis();
if (now >= fadeStartTime) {
// the animation fades the scrollbars out by changing
// the opacity (alpha) from fully opaque to fully
// transparent
int nextFrame = (int) now;
int framesCount = 0;
Interpolator interpolator = scrollBarInterpolator;
// Start opaque
interpolator.setKeyFrame(framesCount++, nextFrame, mOpaque);
// End transparent
nextFrame += scrollBarFadeDuration;
interpolator.setKeyFrame(framesCount, nextFrame, mTransparent);
state = FADING;
// Kick off the fade animation
host.invalidate();
}
}
} }
} }

View File

@ -30,6 +30,16 @@ public class ViewConfiguration {
*/ */
private static final int SCROLL_BAR_SIZE = 10; private static final int SCROLL_BAR_SIZE = 10;
/**
* Duration of the fade when scrollbars fade away in milliseconds
*/
private static final int SCROLL_BAR_FADE_DURATION = 250;
/**
* Default delay before the scrollbars fade in milliseconds
*/
private static final int SCROLL_BAR_DEFAULT_DELAY = 300;
/** /**
* Defines the length of the fading edges in pixels * Defines the length of the fading edges in pixels
*/ */
@ -220,6 +230,20 @@ public class ViewConfiguration {
return mScrollbarSize; return mScrollbarSize;
} }
/**
* @return Duration of the fade when scrollbars fade away in milliseconds
*/
public static int getScrollBarFadeDuration() {
return SCROLL_BAR_FADE_DURATION;
}
/**
* @return Default delay before the scrollbars fade in milliseconds
*/
public static int getScrollDefaultDelay() {
return SCROLL_BAR_DEFAULT_DELAY;
}
/** /**
* @return the length of the fading edges in pixels * @return the length of the fading edges in pixels
* *

View File

@ -2480,6 +2480,7 @@ public class WebView extends AbsoluteLayout
// Log.d(LOGTAG, "startScroll: " + dx + " " + dy); // Log.d(LOGTAG, "startScroll: " + dx + " " + dy);
mScroller.startScroll(mScrollX, mScrollY, dx, dy, mScroller.startScroll(mScrollX, mScrollY, dx, dy,
animationDuration > 0 ? animationDuration : computeDuration(dx, dy)); animationDuration > 0 ? animationDuration : computeDuration(dx, dy));
awakenScrollBars(mScroller.getDuration());
invalidate(); invalidate();
} else { } else {
abortAnimation(); // just in case abortAnimation(); // just in case
@ -4326,6 +4327,7 @@ public class WebView extends AbsoluteLayout
// resume the webcore update. // resume the webcore update.
final int time = mScroller.getDuration(); final int time = mScroller.getDuration();
mPrivateHandler.sendEmptyMessageDelayed(RESUME_WEBCORE_UPDATE, time); mPrivateHandler.sendEmptyMessageDelayed(RESUME_WEBCORE_UPDATE, time);
awakenScrollBars(time);
invalidate(); invalidate();
} }

View File

@ -2444,7 +2444,9 @@ public abstract class AbsListView extends AdapterView<ListAdapter> implements Te
if (spaceAbove >= absIncrementalDeltaY && spaceBelow >= absIncrementalDeltaY) { if (spaceAbove >= absIncrementalDeltaY && spaceBelow >= absIncrementalDeltaY) {
hideSelector(); hideSelector();
offsetChildrenTopAndBottom(incrementalDeltaY); offsetChildrenTopAndBottom(incrementalDeltaY);
invalidate(); if (!awakenScrollBars()) {
invalidate();
}
mMotionViewNewTop = mMotionViewOriginalTop + deltaY; mMotionViewNewTop = mMotionViewOriginalTop + deltaY;
} else { } else {
final int firstPosition = mFirstPosition; final int firstPosition = mFirstPosition;
@ -2527,6 +2529,7 @@ public abstract class AbsListView extends AdapterView<ListAdapter> implements Te
mBlockLayoutRequests = false; mBlockLayoutRequests = false;
invokeOnItemScrollListener(); invokeOnItemScrollListener();
awakenScrollBars();
} }
} }

View File

@ -1340,8 +1340,23 @@ public class GridView extends AbsListView {
*/ */
@Override @Override
void setSelectionInt(int position) { void setSelectionInt(int position) {
int previousSelectedPosition = mNextSelectedPosition;
setNextSelectedPositionInt(position); setNextSelectedPositionInt(position);
layoutChildren(); layoutChildren();
final int next = mStackFromBottom ? mItemCount - 1 - mNextSelectedPosition :
mNextSelectedPosition;
final int previous = mStackFromBottom ? mItemCount - 1
- previousSelectedPosition : previousSelectedPosition;
final int nextRow = next / mNumColumns;
final int previousRow = previous / mNumColumns;
if (nextRow != previousRow) {
awakenScrollBars();
}
} }
@Override @Override
@ -1471,6 +1486,7 @@ public class GridView extends AbsListView {
if (nextPage >= 0) { if (nextPage >= 0) {
setSelectionInt(nextPage); setSelectionInt(nextPage);
invokeOnItemScrollListener(); invokeOnItemScrollListener();
awakenScrollBars();
return true; return true;
} }
@ -1497,6 +1513,10 @@ public class GridView extends AbsListView {
invokeOnItemScrollListener(); invokeOnItemScrollListener();
moved = true; moved = true;
} }
if (moved) {
awakenScrollBars();
}
return moved; return moved;
} }
@ -1563,6 +1583,10 @@ public class GridView extends AbsListView {
invokeOnItemScrollListener(); invokeOnItemScrollListener();
} }
if (moved) {
awakenScrollBars();
}
return moved; return moved;
} }

View File

@ -829,6 +829,7 @@ public class HorizontalScrollView extends FrameLayout {
long duration = AnimationUtils.currentAnimationTimeMillis() - mLastScroll; long duration = AnimationUtils.currentAnimationTimeMillis() - mLastScroll;
if (duration > ANIMATED_SCROLL_GAP) { if (duration > ANIMATED_SCROLL_GAP) {
mScroller.startScroll(mScrollX, mScrollY, dx, dy); mScroller.startScroll(mScrollX, mScrollY, dx, dy);
awakenScrollBars(mScroller.getDuration());
invalidate(); invalidate();
} else { } else {
if (!mScroller.isFinished()) { if (!mScroller.isFinished()) {
@ -1172,6 +1173,7 @@ public class HorizontalScrollView extends FrameLayout {
mScrollViewMovedFocus = false; mScrollViewMovedFocus = false;
} }
awakenScrollBars(mScroller.getDuration());
invalidate(); invalidate();
} }
} }

View File

@ -1818,13 +1818,29 @@ public class ListView extends AbsListView {
/** /**
* Makes the item at the supplied position selected. * Makes the item at the supplied position selected.
* *
* @param position the position of the item to select * @param position the position of the item to select
*/ */
@Override @Override
void setSelectionInt(int position) { void setSelectionInt(int position) {
setNextSelectedPositionInt(position); setNextSelectedPositionInt(position);
boolean awakeScrollbars = false;
final int selectedPosition = mSelectedPosition;
if (selectedPosition >= 0) {
if (position == selectedPosition - 1) {
awakeScrollbars = true;
} else if (position == selectedPosition + 1) {
awakeScrollbars = true;
}
}
layoutChildren(); layoutChildren();
if (awakeScrollbars) {
awakenScrollBars();
}
} }
/** /**
@ -2084,7 +2100,9 @@ public class ListView extends AbsListView {
setSelectionInt(position); setSelectionInt(position);
invokeOnItemScrollListener(); invokeOnItemScrollListener();
invalidate(); if (!awakenScrollBars()) {
invalidate();
}
return true; return true;
} }
@ -2125,7 +2143,8 @@ public class ListView extends AbsListView {
} }
} }
if (moved) { if (moved && !awakenScrollBars()) {
awakenScrollBars();
invalidate(); invalidate();
} }
@ -2270,7 +2289,9 @@ public class ListView extends AbsListView {
positionSelector(selectedView); positionSelector(selectedView);
mSelectedTop = selectedView.getTop(); mSelectedTop = selectedView.getTop();
} }
invalidate(); if (!awakenScrollBars()) {
invalidate();
}
invokeOnItemScrollListener(); invokeOnItemScrollListener();
return true; return true;
} }

View File

@ -832,6 +832,7 @@ public class ScrollView extends FrameLayout {
long duration = AnimationUtils.currentAnimationTimeMillis() - mLastScroll; long duration = AnimationUtils.currentAnimationTimeMillis() - mLastScroll;
if (duration > ANIMATED_SCROLL_GAP) { if (duration > ANIMATED_SCROLL_GAP) {
mScroller.startScroll(mScrollX, mScrollY, dx, dy); mScroller.startScroll(mScrollX, mScrollY, dx, dy);
awakenScrollBars(mScroller.getDuration());
invalidate(); invalidate();
} else { } else {
if (!mScroller.isFinished()) { if (!mScroller.isFinished()) {
@ -1175,6 +1176,7 @@ public class ScrollView extends FrameLayout {
mScrollViewMovedFocus = false; mScrollViewMovedFocus = false;
} }
awakenScrollBars(mScroller.getDuration());
invalidate(); invalidate();
} }
} }

View File

@ -5572,6 +5572,7 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
if (duration > ANIMATED_SCROLL_GAP) { if (duration > ANIMATED_SCROLL_GAP) {
mScroller.startScroll(mScrollX, mScrollY, dx, dy); mScroller.startScroll(mScrollX, mScrollY, dx, dy);
awakenScrollBars(mScroller.getDuration());
invalidate(); invalidate();
} else { } else {
if (!mScroller.isFinished()) { if (!mScroller.isFinished()) {

View File

@ -1162,6 +1162,12 @@
set, else it will be false. --> set, else it will be false. -->
<attr name="isScrollContainer" format="boolean" /> <attr name="isScrollContainer" format="boolean" />
<!-- Defines whether to fade out scrollbars when they are not in use. -->
<attr name="fadeScrollbars" format="boolean" />
<!-- Defines the delay in milliseconds that a scrollbar takes to fade out. -->
<attr name="scrollbarFadeDuration" format="integer" />
<!-- Defines the delay in milliseconds that a scrollbar waits before fade out. -->
<attr name="scrollbarDefaultDelayBeforeFade" format="integer" />
<!-- Sets the width of vertical scrollbars and height of horizontal scrollbars. --> <!-- Sets the width of vertical scrollbars and height of horizontal scrollbars. -->
<attr name="scrollbarSize" format="dimension" /> <attr name="scrollbarSize" format="dimension" />
<!-- Defines the horizontal scrollbar thumb drawable. --> <!-- Defines the horizontal scrollbar thumb drawable. -->

View File

@ -1172,7 +1172,10 @@
<public type="attr" name="thumbnail" /> <public type="attr" name="thumbnail" />
<public type="attr" name="detachWallpaper" /> <public type="attr" name="detachWallpaper" />
<public type="attr" name="finishOnCloseSystemDialogs" /> <public type="attr" name="finishOnCloseSystemDialogs" />
<public type="attr" name="scrollbarFadeDuration" />
<public type="attr" name="scrollbarDefaultDelayBeforeFade" />
<public type="attr" name="fadeScrollbars" />
<public type="style" name="Theme.Wallpaper" /> <public type="style" name="Theme.Wallpaper" />
<public type="style" name="Theme.Wallpaper.NoTitleBar" /> <public type="style" name="Theme.Wallpaper.NoTitleBar" />
<public type="style" name="Theme.Wallpaper.NoTitleBar.Fullscreen" /> <public type="style" name="Theme.Wallpaper.NoTitleBar.Fullscreen" />

View File

@ -126,6 +126,8 @@
<item name="panelTextAppearance">?android:attr/textAppearanceInverse</item> <item name="panelTextAppearance">?android:attr/textAppearanceInverse</item>
<!-- Scrollbar attributes --> <!-- Scrollbar attributes -->
<item name="scrollbarFadeDuration">250</item>
<item name="scrollbarDefaultDelayBeforeFade">300</item>
<item name="scrollbarSize">10dip</item> <item name="scrollbarSize">10dip</item>
<item name="scrollbarThumbHorizontal">@android:drawable/scrollbar_handle_horizontal</item> <item name="scrollbarThumbHorizontal">@android:drawable/scrollbar_handle_horizontal</item>
<item name="scrollbarThumbVertical">@android:drawable/scrollbar_handle_vertical</item> <item name="scrollbarThumbVertical">@android:drawable/scrollbar_handle_vertical</item>