• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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.annotation.NonNull;
20 import android.graphics.Canvas;
21 import android.graphics.ColorFilter;
22 import android.graphics.PixelFormat;
23 import android.graphics.Rect;
24 import android.graphics.drawable.Drawable;
25 
26 import com.android.internal.widget.ScrollBarUtils;
27 
28 /**
29  * This is only used by View for displaying its scroll bars. It should probably
30  * be moved in to the view package since it is used in that lower-level layer.
31  * For now, we'll hide it so it can be cleaned up later.
32  *
33  * {@hide}
34  */
35 public class ScrollBarDrawable extends Drawable implements Drawable.Callback {
36     private Drawable mVerticalTrack;
37     private Drawable mHorizontalTrack;
38     private Drawable mVerticalThumb;
39     private Drawable mHorizontalThumb;
40 
41     private int mRange;
42     private int mOffset;
43     private int mExtent;
44 
45     private boolean mVertical;
46     private boolean mBoundsChanged;
47     private boolean mRangeChanged;
48     private boolean mAlwaysDrawHorizontalTrack;
49     private boolean mAlwaysDrawVerticalTrack;
50     private boolean mMutated;
51 
52     private int mAlpha = 255;
53     private boolean mHasSetAlpha;
54 
55     private ColorFilter mColorFilter;
56     private boolean mHasSetColorFilter;
57 
58     /**
59      * Indicate whether the horizontal scrollbar track should always be drawn
60      * regardless of the extent. Defaults to false.
61      *
62      * @param alwaysDrawTrack Whether the track should always be drawn
63      *
64      * @see #getAlwaysDrawHorizontalTrack()
65      */
setAlwaysDrawHorizontalTrack(boolean alwaysDrawTrack)66     public void setAlwaysDrawHorizontalTrack(boolean alwaysDrawTrack) {
67         mAlwaysDrawHorizontalTrack = alwaysDrawTrack;
68     }
69 
70     /**
71      * Indicate whether the vertical scrollbar track should always be drawn
72      * regardless of the extent. Defaults to false.
73      *
74      * @param alwaysDrawTrack Whether the track should always be drawn
75      *
76      * @see #getAlwaysDrawVerticalTrack()
77      */
setAlwaysDrawVerticalTrack(boolean alwaysDrawTrack)78     public void setAlwaysDrawVerticalTrack(boolean alwaysDrawTrack) {
79         mAlwaysDrawVerticalTrack = alwaysDrawTrack;
80     }
81 
82     /**
83      * @return whether the vertical scrollbar track should always be drawn
84      *         regardless of the extent.
85      *
86      * @see #setAlwaysDrawVerticalTrack(boolean)
87      */
getAlwaysDrawVerticalTrack()88     public boolean getAlwaysDrawVerticalTrack() {
89         return mAlwaysDrawVerticalTrack;
90     }
91 
92     /**
93      * @return whether the horizontal scrollbar track should always be drawn
94      *         regardless of the extent.
95      *
96      * @see #setAlwaysDrawHorizontalTrack(boolean)
97      */
getAlwaysDrawHorizontalTrack()98     public boolean getAlwaysDrawHorizontalTrack() {
99         return mAlwaysDrawHorizontalTrack;
100     }
101 
setParameters(int range, int offset, int extent, boolean vertical)102     public void setParameters(int range, int offset, int extent, boolean vertical) {
103         if (mVertical != vertical) {
104             mVertical = vertical;
105 
106             mBoundsChanged = true;
107         }
108 
109         if (mRange != range || mOffset != offset || mExtent != extent) {
110             mRange = range;
111             mOffset = offset;
112             mExtent = extent;
113 
114             mRangeChanged = true;
115         }
116     }
117 
118     @Override
draw(Canvas canvas)119     public void draw(Canvas canvas) {
120         final boolean vertical = mVertical;
121         final int extent = mExtent;
122         final int range = mRange;
123 
124         boolean drawTrack = true;
125         boolean drawThumb = true;
126         if (extent <= 0 || range <= extent) {
127             drawTrack = vertical ? mAlwaysDrawVerticalTrack : mAlwaysDrawHorizontalTrack;
128             drawThumb = false;
129         }
130 
131         final Rect r = getBounds();
132         if (canvas.quickReject(r.left, r.top, r.right, r.bottom, Canvas.EdgeType.AA)) {
133             return;
134         }
135 
136         if (drawTrack) {
137             drawTrack(canvas, r, vertical);
138         }
139 
140         if (drawThumb) {
141             final int scrollBarLength = vertical ? r.height() : r.width();
142             final int thickness = vertical ? r.width() : r.height();
143             final int thumbLength =
144                     ScrollBarUtils.getThumbLength(scrollBarLength, thickness, extent, range);
145             final int thumbOffset =
146                     ScrollBarUtils.getThumbOffset(scrollBarLength, thumbLength, extent, range,
147                             mOffset);
148 
149             drawThumb(canvas, r, thumbOffset, thumbLength, vertical);
150         }
151     }
152 
153     @Override
onBoundsChange(Rect bounds)154     protected void onBoundsChange(Rect bounds) {
155         super.onBoundsChange(bounds);
156         mBoundsChanged = true;
157     }
158 
159     @Override
isStateful()160     public boolean isStateful() {
161         return (mVerticalTrack != null && mVerticalTrack.isStateful())
162                 || (mVerticalThumb != null && mVerticalThumb.isStateful())
163                 || (mHorizontalTrack != null && mHorizontalTrack.isStateful())
164                 || (mHorizontalThumb != null && mHorizontalThumb.isStateful())
165                 || super.isStateful();
166     }
167 
168     @Override
onStateChange(int[] state)169     protected boolean onStateChange(int[] state) {
170         boolean changed = super.onStateChange(state);
171         if (mVerticalTrack != null) {
172             changed |= mVerticalTrack.setState(state);
173         }
174         if (mVerticalThumb != null) {
175             changed |= mVerticalThumb.setState(state);
176         }
177         if (mHorizontalTrack != null) {
178             changed |= mHorizontalTrack.setState(state);
179         }
180         if (mHorizontalThumb != null) {
181             changed |= mHorizontalThumb.setState(state);
182         }
183         return changed;
184     }
185 
drawTrack(Canvas canvas, Rect bounds, boolean vertical)186     private void drawTrack(Canvas canvas, Rect bounds, boolean vertical) {
187         final Drawable track;
188         if (vertical) {
189             track = mVerticalTrack;
190         } else {
191             track = mHorizontalTrack;
192         }
193 
194         if (track != null) {
195             if (mBoundsChanged) {
196                 track.setBounds(bounds);
197             }
198             track.draw(canvas);
199         }
200     }
201 
drawThumb(Canvas canvas, Rect bounds, int offset, int length, boolean vertical)202     private void drawThumb(Canvas canvas, Rect bounds, int offset, int length, boolean vertical) {
203         final boolean changed = mRangeChanged || mBoundsChanged;
204         if (vertical) {
205             if (mVerticalThumb != null) {
206                 final Drawable thumb = mVerticalThumb;
207                 if (changed) {
208                     thumb.setBounds(bounds.left, bounds.top + offset,
209                             bounds.right, bounds.top + offset + length);
210                 }
211 
212                 thumb.draw(canvas);
213             }
214         } else {
215             if (mHorizontalThumb != null) {
216                 final Drawable thumb = mHorizontalThumb;
217                 if (changed) {
218                     thumb.setBounds(bounds.left + offset, bounds.top,
219                             bounds.left + offset + length, bounds.bottom);
220                 }
221 
222                 thumb.draw(canvas);
223             }
224         }
225     }
226 
setVerticalThumbDrawable(Drawable thumb)227     public void setVerticalThumbDrawable(Drawable thumb) {
228         if (mVerticalThumb != null) {
229             mVerticalThumb.setCallback(null);
230         }
231 
232         propagateCurrentState(thumb);
233         mVerticalThumb = thumb;
234     }
235 
setVerticalTrackDrawable(Drawable track)236     public void setVerticalTrackDrawable(Drawable track) {
237         if (mVerticalTrack != null) {
238             mVerticalTrack.setCallback(null);
239         }
240 
241         propagateCurrentState(track);
242         mVerticalTrack = track;
243     }
244 
setHorizontalThumbDrawable(Drawable thumb)245     public void setHorizontalThumbDrawable(Drawable thumb) {
246         if (mHorizontalThumb != null) {
247             mHorizontalThumb.setCallback(null);
248         }
249 
250         propagateCurrentState(thumb);
251         mHorizontalThumb = thumb;
252     }
253 
setHorizontalTrackDrawable(Drawable track)254     public void setHorizontalTrackDrawable(Drawable track) {
255         if (mHorizontalTrack != null) {
256             mHorizontalTrack.setCallback(null);
257         }
258 
259         propagateCurrentState(track);
260         mHorizontalTrack = track;
261     }
262 
propagateCurrentState(Drawable d)263     private void propagateCurrentState(Drawable d) {
264         if (d != null) {
265             if (mMutated) {
266                 d.mutate();
267             }
268 
269             d.setState(getState());
270             d.setCallback(this);
271 
272             if (mHasSetAlpha) {
273                 d.setAlpha(mAlpha);
274             }
275 
276             if (mHasSetColorFilter) {
277                 d.setColorFilter(mColorFilter);
278             }
279         }
280     }
281 
getSize(boolean vertical)282     public int getSize(boolean vertical) {
283         if (vertical) {
284             return mVerticalTrack != null ? mVerticalTrack.getIntrinsicWidth() :
285                     mVerticalThumb != null ? mVerticalThumb.getIntrinsicWidth() : 0;
286         } else {
287             return mHorizontalTrack != null ? mHorizontalTrack.getIntrinsicHeight() :
288                     mHorizontalThumb != null ? mHorizontalThumb.getIntrinsicHeight() : 0;
289         }
290     }
291 
292     @Override
mutate()293     public ScrollBarDrawable mutate() {
294         if (!mMutated && super.mutate() == this) {
295             if (mVerticalTrack != null) {
296                 mVerticalTrack.mutate();
297             }
298             if (mVerticalThumb != null) {
299                 mVerticalThumb.mutate();
300             }
301             if (mHorizontalTrack != null) {
302                 mHorizontalTrack.mutate();
303             }
304             if (mHorizontalThumb != null) {
305                 mHorizontalThumb.mutate();
306             }
307             mMutated = true;
308         }
309         return this;
310     }
311 
312     @Override
setAlpha(int alpha)313     public void setAlpha(int alpha) {
314         mAlpha = alpha;
315         mHasSetAlpha = true;
316 
317         if (mVerticalTrack != null) {
318             mVerticalTrack.setAlpha(alpha);
319         }
320         if (mVerticalThumb != null) {
321             mVerticalThumb.setAlpha(alpha);
322         }
323         if (mHorizontalTrack != null) {
324             mHorizontalTrack.setAlpha(alpha);
325         }
326         if (mHorizontalThumb != null) {
327             mHorizontalThumb.setAlpha(alpha);
328         }
329     }
330 
331     @Override
getAlpha()332     public int getAlpha() {
333         return mAlpha;
334     }
335 
336     @Override
setColorFilter(ColorFilter colorFilter)337     public void setColorFilter(ColorFilter colorFilter) {
338         mColorFilter = colorFilter;
339         mHasSetColorFilter = true;
340 
341         if (mVerticalTrack != null) {
342             mVerticalTrack.setColorFilter(colorFilter);
343         }
344         if (mVerticalThumb != null) {
345             mVerticalThumb.setColorFilter(colorFilter);
346         }
347         if (mHorizontalTrack != null) {
348             mHorizontalTrack.setColorFilter(colorFilter);
349         }
350         if (mHorizontalThumb != null) {
351             mHorizontalThumb.setColorFilter(colorFilter);
352         }
353     }
354 
355     @Override
getColorFilter()356     public ColorFilter getColorFilter() {
357         return mColorFilter;
358     }
359 
360     @Override
getOpacity()361     public int getOpacity() {
362         return PixelFormat.TRANSLUCENT;
363     }
364 
365     @Override
invalidateDrawable(@onNull Drawable who)366     public void invalidateDrawable(@NonNull Drawable who) {
367         invalidateSelf();
368     }
369 
370     @Override
scheduleDrawable(@onNull Drawable who, @NonNull Runnable what, long when)371     public void scheduleDrawable(@NonNull Drawable who, @NonNull Runnable what, long when) {
372         scheduleSelf(what, when);
373     }
374 
375     @Override
unscheduleDrawable(@onNull Drawable who, @NonNull Runnable what)376     public void unscheduleDrawable(@NonNull Drawable who, @NonNull Runnable what) {
377         unscheduleSelf(what);
378     }
379 
380     @Override
toString()381     public String toString() {
382         return "ScrollBarDrawable: range=" + mRange + " offset=" + mOffset +
383                " extent=" + mExtent + (mVertical ? " V" : " H");
384     }
385 }
386 
387 
388