1 package com.github.mikephil.charting.utils; 2 3 import android.graphics.Canvas; 4 import android.graphics.LinearGradient; 5 import android.graphics.Paint; 6 import android.graphics.Path; 7 import android.graphics.RectF; 8 import android.graphics.drawable.Drawable; 9 10 import androidx.annotation.NonNull; 11 import androidx.annotation.Nullable; 12 13 public class Fill 14 { 15 public enum Type 16 { 17 EMPTY, COLOR, LINEAR_GRADIENT, DRAWABLE 18 } 19 20 public enum Direction 21 { 22 DOWN, UP, RIGHT, LEFT 23 } 24 25 /** 26 * the type of fill 27 */ 28 private Type mType = Type.EMPTY; 29 30 /** 31 * the color that is used for filling 32 */ 33 @Nullable 34 private Integer mColor = null; 35 36 private Integer mFinalColor = null; 37 38 /** 39 * the drawable to be used for filling 40 */ 41 @Nullable 42 protected Drawable mDrawable; 43 44 @Nullable 45 private int[] mGradientColors; 46 47 @Nullable 48 private float[] mGradientPositions; 49 50 /** 51 * transparency used for filling 52 */ 53 private int mAlpha = 255; 54 Fill()55 public Fill() 56 { 57 } 58 Fill(int color)59 public Fill(int color) 60 { 61 this.mType = Type.COLOR; 62 this.mColor = color; 63 calculateFinalColor(); 64 } 65 Fill(int startColor, int endColor)66 public Fill(int startColor, int endColor) 67 { 68 this.mType = Type.LINEAR_GRADIENT; 69 this.mGradientColors = new int[]{startColor, endColor}; 70 } 71 Fill(@onNull int[] gradientColors)72 public Fill(@NonNull int[] gradientColors) 73 { 74 this.mType = Type.LINEAR_GRADIENT; 75 this.mGradientColors = gradientColors; 76 } 77 Fill(@onNull int[] gradientColors, @NonNull float[] gradientPositions)78 public Fill(@NonNull int[] gradientColors, @NonNull float[] gradientPositions) 79 { 80 this.mType = Type.LINEAR_GRADIENT; 81 this.mGradientColors = gradientColors; 82 this.mGradientPositions = gradientPositions; 83 } 84 Fill(@onNull Drawable drawable)85 public Fill(@NonNull Drawable drawable) 86 { 87 this.mType = Type.DRAWABLE; 88 this.mDrawable = drawable; 89 } 90 getType()91 public Type getType() 92 { 93 return mType; 94 } 95 setType(Type type)96 public void setType(Type type) 97 { 98 this.mType = type; 99 } 100 101 @Nullable getColor()102 public Integer getColor() 103 { 104 return mColor; 105 } 106 setColor(int color)107 public void setColor(int color) 108 { 109 this.mColor = color; 110 calculateFinalColor(); 111 } 112 getGradientColors()113 public int[] getGradientColors() 114 { 115 return mGradientColors; 116 } 117 setGradientColors(int[] colors)118 public void setGradientColors(int[] colors) 119 { 120 this.mGradientColors = colors; 121 } 122 getGradientPositions()123 public float[] getGradientPositions() 124 { 125 return mGradientPositions; 126 } 127 setGradientPositions(float[] positions)128 public void setGradientPositions(float[] positions) 129 { 130 this.mGradientPositions = positions; 131 } 132 setGradientColors(int startColor, int endColor)133 public void setGradientColors(int startColor, int endColor) 134 { 135 this.mGradientColors = new int[]{startColor, endColor}; 136 } 137 getAlpha()138 public int getAlpha() 139 { 140 return mAlpha; 141 } 142 setAlpha(int alpha)143 public void setAlpha(int alpha) 144 { 145 this.mAlpha = alpha; 146 calculateFinalColor(); 147 } 148 calculateFinalColor()149 private void calculateFinalColor() 150 { 151 if (mColor == null) 152 { 153 mFinalColor = null; 154 } else 155 { 156 int alpha = (int) Math.floor(((mColor >> 24) / 255.0) * (mAlpha / 255.0) * 255.0); 157 mFinalColor = (alpha << 24) | (mColor & 0xffffff); 158 } 159 } 160 fillRect(Canvas c, Paint paint, float left, float top, float right, float bottom, Direction gradientDirection)161 public void fillRect(Canvas c, Paint paint, 162 float left, float top, float right, float bottom, 163 Direction gradientDirection) 164 { 165 switch (mType) 166 { 167 case EMPTY: 168 return; 169 170 case COLOR: 171 { 172 if (mFinalColor == null) return; 173 174 if (isClipPathSupported()) 175 { 176 int save = c.save(); 177 178 c.clipRect(left, top, right, bottom); 179 c.drawColor(mFinalColor); 180 181 c.restoreToCount(save); 182 } 183 else 184 { 185 // save 186 Paint.Style previous = paint.getStyle(); 187 int previousColor = paint.getColor(); 188 189 // set 190 paint.setStyle(Paint.Style.FILL); 191 paint.setColor(mFinalColor); 192 193 c.drawRect(left, top, right, bottom, paint); 194 195 // restore 196 paint.setColor(previousColor); 197 paint.setStyle(previous); 198 } 199 } 200 break; 201 202 case LINEAR_GRADIENT: 203 { 204 if (mGradientColors == null) return; 205 206 LinearGradient gradient = new LinearGradient( 207 (int) (gradientDirection == Direction.RIGHT 208 ? right 209 : gradientDirection == Direction.LEFT 210 ? left 211 : left), 212 (int) (gradientDirection == Direction.UP 213 ? bottom 214 : gradientDirection == Direction.DOWN 215 ? top 216 : top), 217 (int) (gradientDirection == Direction.RIGHT 218 ? left 219 : gradientDirection == Direction.LEFT 220 ? right 221 : left), 222 (int) (gradientDirection == Direction.UP 223 ? top 224 : gradientDirection == Direction.DOWN 225 ? bottom 226 : top), 227 mGradientColors, 228 mGradientPositions, 229 android.graphics.Shader.TileMode.MIRROR); 230 231 paint.setShader(gradient); 232 233 c.drawRect(left, top, right, bottom, paint); 234 } 235 break; 236 237 case DRAWABLE: 238 { 239 if (mDrawable == null) return; 240 241 mDrawable.setBounds((int) left, (int) top, (int) right, (int) bottom); 242 mDrawable.draw(c); 243 } 244 break; 245 } 246 } 247 fillPath(Canvas c, Path path, Paint paint, @Nullable RectF clipRect)248 public void fillPath(Canvas c, Path path, Paint paint, 249 @Nullable RectF clipRect) 250 { 251 switch (mType) 252 { 253 case EMPTY: 254 return; 255 256 case COLOR: 257 { 258 if (mFinalColor == null) return; 259 260 if (clipRect != null && isClipPathSupported()) 261 { 262 int save = c.save(); 263 264 c.clipPath(path); 265 c.drawColor(mFinalColor); 266 267 c.restoreToCount(save); 268 } 269 else 270 { 271 // save 272 Paint.Style previous = paint.getStyle(); 273 int previousColor = paint.getColor(); 274 275 // set 276 paint.setStyle(Paint.Style.FILL); 277 paint.setColor(mFinalColor); 278 279 c.drawPath(path, paint); 280 281 // restore 282 paint.setColor(previousColor); 283 paint.setStyle(previous); 284 } 285 } 286 break; 287 288 case LINEAR_GRADIENT: 289 { 290 if (mGradientColors == null) return; 291 292 LinearGradient gradient = new LinearGradient( 293 0, 294 0, 295 c.getWidth(), 296 c.getHeight(), 297 mGradientColors, 298 mGradientPositions, 299 android.graphics.Shader.TileMode.MIRROR); 300 301 paint.setShader(gradient); 302 303 c.drawPath(path, paint); 304 } 305 break; 306 307 case DRAWABLE: 308 { 309 if (mDrawable == null) return; 310 311 ensureClipPathSupported(); 312 313 int save = c.save(); 314 c.clipPath(path); 315 316 mDrawable.setBounds( 317 clipRect == null ? 0 : (int) clipRect.left, 318 clipRect == null ? 0 : (int) clipRect.top, 319 clipRect == null ? c.getWidth() : (int) clipRect.right, 320 clipRect == null ? c.getHeight() : (int) clipRect.bottom); 321 mDrawable.draw(c); 322 323 c.restoreToCount(save); 324 } 325 break; 326 } 327 } 328 isClipPathSupported()329 private boolean isClipPathSupported() 330 { 331 return Utils.getSDKInt() >= 18; 332 } 333 ensureClipPathSupported()334 private void ensureClipPathSupported() 335 { 336 if (Utils.getSDKInt() < 18) 337 { 338 throw new RuntimeException("Fill-drawables not (yet) supported below API level 18, " + 339 "this code was run on API level " + Utils.getSDKInt() + "."); 340 } 341 } 342 } 343