ScrollBarDrawable.java revision 03748a5707fe3d1f071226ea3caf571abdc0d25d
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 17package android.widget; 18 19import android.graphics.Canvas; 20import android.graphics.ColorFilter; 21import android.graphics.PixelFormat; 22import android.graphics.Rect; 23import android.graphics.drawable.Drawable; 24 25/** 26 * This is only used by View for displaying its scroll bars. It should probably 27 * be moved in to the view package since it is used in that lower-level layer. 28 * For now, we'll hide it so it can be cleaned up later. 29 * {@hide} 30 */ 31public class ScrollBarDrawable extends Drawable { 32 private static final int[] STATE_ENABLED = new int[] { android.R.attr.state_enabled }; 33 34 private Drawable mVerticalTrack; 35 private Drawable mHorizontalTrack; 36 private Drawable mVerticalThumb; 37 private Drawable mHorizontalThumb; 38 private int mRange; 39 private int mOffset; 40 private int mExtent; 41 private boolean mVertical; 42 private boolean mChanged; 43 private boolean mRangeChanged; 44 private final Rect mTempBounds = new Rect(); 45 private boolean mAlwaysDrawHorizontalTrack; 46 private boolean mAlwaysDrawVerticalTrack; 47 48 public ScrollBarDrawable() { 49 } 50 51 /** 52 * Indicate whether the horizontal scrollbar track should always be drawn regardless of the 53 * extent. Defaults to false. 54 * 55 * @param alwaysDrawTrack Set to true if the track should always be drawn 56 */ 57 public void setAlwaysDrawHorizontalTrack(boolean alwaysDrawTrack) { 58 mAlwaysDrawHorizontalTrack = alwaysDrawTrack; 59 } 60 61 /** 62 * Indicate whether the vertical scrollbar track should always be drawn regardless of the 63 * extent. Defaults to false. 64 * 65 * @param alwaysDrawTrack Set to true if the track should always be drawn 66 */ 67 public void setAlwaysDrawVerticalTrack(boolean alwaysDrawTrack) { 68 mAlwaysDrawVerticalTrack = alwaysDrawTrack; 69 } 70 71 /** 72 * Indicates whether the vertical scrollbar track should always be drawn regardless of the 73 * extent. 74 */ 75 public boolean getAlwaysDrawVerticalTrack() { 76 return mAlwaysDrawVerticalTrack; 77 } 78 79 /** 80 * Indicates whether the horizontal scrollbar track should always be drawn regardless of the 81 * extent. 82 */ 83 public boolean getAlwaysDrawHorizontalTrack() { 84 return mAlwaysDrawHorizontalTrack; 85 } 86 87 public void setParameters(int range, int offset, int extent, boolean vertical) { 88 if (mVertical != vertical) { 89 mChanged = true; 90 } 91 92 if (mRange != range || mOffset != offset || mExtent != extent) { 93 mRangeChanged = true; 94 } 95 96 mRange = range; 97 mOffset = offset; 98 mExtent = extent; 99 mVertical = vertical; 100 } 101 102 @Override 103 public void draw(Canvas canvas) { 104 final boolean vertical = mVertical; 105 final int extent = mExtent; 106 final int range = mRange; 107 108 boolean drawTrack = true; 109 boolean drawThumb = true; 110 if (extent <= 0 || range <= extent) { 111 drawTrack = vertical ? mAlwaysDrawVerticalTrack : mAlwaysDrawHorizontalTrack; 112 drawThumb = false; 113 } 114 115 Rect r = getBounds(); 116 if (canvas.quickReject(r.left, r.top, r.right, r.bottom, Canvas.EdgeType.AA)) { 117 return; 118 } 119 if (drawTrack) { 120 drawTrack(canvas, r, vertical); 121 } 122 123 if (drawThumb) { 124 int size = vertical ? r.height() : r.width(); 125 int thickness = vertical ? r.width() : r.height(); 126 int length = Math.round((float) size * extent / range); 127 int offset = Math.round((float) (size - length) * mOffset / (range - extent)); 128 129 // avoid the tiny thumb 130 int minLength = thickness * 2; 131 if (length < minLength) { 132 length = minLength; 133 } 134 // avoid the too-big thumb 135 if (offset + length > size) { 136 offset = size - length; 137 } 138 139 drawThumb(canvas, r, offset, length, vertical); 140 } 141 } 142 143 @Override 144 protected void onBoundsChange(Rect bounds) { 145 super.onBoundsChange(bounds); 146 mChanged = true; 147 } 148 149 protected void drawTrack(Canvas canvas, Rect bounds, boolean vertical) { 150 Drawable track; 151 if (vertical) { 152 track = mVerticalTrack; 153 } else { 154 track = mHorizontalTrack; 155 } 156 if (track != null) { 157 if (mChanged) { 158 track.setBounds(bounds); 159 } 160 track.draw(canvas); 161 } 162 } 163 164 protected void drawThumb(Canvas canvas, Rect bounds, int offset, int length, boolean vertical) { 165 final Rect thumbRect = mTempBounds; 166 final boolean changed = mRangeChanged || mChanged; 167 if (changed) { 168 if (vertical) { 169 thumbRect.set(bounds.left, bounds.top + offset, 170 bounds.right, bounds.top + offset + length); 171 } else { 172 thumbRect.set(bounds.left + offset, bounds.top, 173 bounds.left + offset + length, bounds.bottom); 174 } 175 } 176 177 if (vertical) { 178 if (mVerticalThumb != null) { 179 final Drawable thumb = mVerticalThumb; 180 if (changed) thumb.setBounds(thumbRect); 181 thumb.draw(canvas); 182 } 183 } else { 184 if (mHorizontalThumb != null) { 185 final Drawable thumb = mHorizontalThumb; 186 if (changed) thumb.setBounds(thumbRect); 187 thumb.draw(canvas); 188 } 189 } 190 } 191 192 public void setVerticalThumbDrawable(Drawable thumb) { 193 if (thumb != null) { 194 thumb.setState(STATE_ENABLED); 195 mVerticalThumb = thumb; 196 } 197 } 198 199 public void setVerticalTrackDrawable(Drawable track) { 200 if (track != null) { 201 track.setState(STATE_ENABLED); 202 } 203 mVerticalTrack = track; 204 } 205 206 public void setHorizontalThumbDrawable(Drawable thumb) { 207 if (thumb != null) { 208 thumb.setState(STATE_ENABLED); 209 mHorizontalThumb = thumb; 210 } 211 } 212 213 public void setHorizontalTrackDrawable(Drawable track) { 214 if (track != null) { 215 track.setState(STATE_ENABLED); 216 } 217 mHorizontalTrack = track; 218 } 219 220 public int getSize(boolean vertical) { 221 if (vertical) { 222 return mVerticalTrack != null ? mVerticalTrack.getIntrinsicWidth() : 223 mVerticalThumb != null ? mVerticalThumb.getIntrinsicWidth() : 0; 224 } else { 225 return mHorizontalTrack != null ? mHorizontalTrack.getIntrinsicHeight() : 226 mHorizontalThumb != null ? mHorizontalThumb.getIntrinsicHeight() : 0; 227 } 228 } 229 230 @Override 231 public void setAlpha(int alpha) { 232 if (mVerticalTrack != null) { 233 mVerticalTrack.setAlpha(alpha); 234 } 235 if (mVerticalThumb != null) { 236 mVerticalThumb.setAlpha(alpha); 237 } 238 if (mHorizontalTrack != null) { 239 mHorizontalTrack.setAlpha(alpha); 240 } 241 if (mHorizontalThumb != null) { 242 mHorizontalThumb.setAlpha(alpha); 243 } 244 } 245 246 @Override 247 public int getAlpha() { 248 // All elements should have same alpha, just return one of them 249 return mVerticalThumb.getAlpha(); 250 } 251 252 @Override 253 public void setColorFilter(ColorFilter cf) { 254 if (mVerticalTrack != null) { 255 mVerticalTrack.setColorFilter(cf); 256 } 257 if (mVerticalThumb != null) { 258 mVerticalThumb.setColorFilter(cf); 259 } 260 if (mHorizontalTrack != null) { 261 mHorizontalTrack.setColorFilter(cf); 262 } 263 if (mHorizontalThumb != null) { 264 mHorizontalThumb.setColorFilter(cf); 265 } 266 } 267 268 @Override 269 public int getOpacity() { 270 return PixelFormat.TRANSLUCENT; 271 } 272 273 @Override 274 public String toString() { 275 return "ScrollBarDrawable: range=" + mRange + " offset=" + mOffset + 276 " extent=" + mExtent + (mVertical ? " V" : " H"); 277 } 278} 279 280 281