TileDrawable.java revision cd728097ff189542877a2952879a3aa3c6cb5666
1/* 2 * Copyright (C) 2013 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 com.android.bitmap.drawable; 18 19import android.animation.ValueAnimator; 20import android.animation.ValueAnimator.AnimatorUpdateListener; 21import android.graphics.Canvas; 22import android.graphics.Color; 23import android.graphics.ColorFilter; 24import android.graphics.Paint; 25import android.graphics.Rect; 26import android.graphics.drawable.Drawable; 27 28import com.android.bitmap.drawable.ExtendedBitmapDrawable.ExtendedOptions; 29 30/** 31 * A drawable that wraps another drawable and places it in the center of this space. This drawable 32 * allows a background color for the "tile", and has a fade-out transition when 33 * {@link #setVisible(boolean, boolean)} indicates that it is no longer visible. 34 */ 35public class TileDrawable extends Drawable implements Drawable.Callback { 36 37 private final ExtendedOptions mOpts; 38 private final Paint mPaint = new Paint(); 39 private final Drawable mInner; 40 private final int mInnerWidth; 41 private final int mInnerHeight; 42 43 protected final ValueAnimator mFadeOutAnimator; 44 45 public TileDrawable(Drawable inner, int innerWidth, int innerHeight, int fadeOutDurationMs, 46 ExtendedOptions opts) { 47 mOpts = opts; 48 mInner = inner != null ? inner.mutate() : null; 49 mInnerWidth = innerWidth; 50 mInnerHeight = innerHeight; 51 if (inner != null) { 52 mInner.setCallback(this); 53 } 54 55 mFadeOutAnimator = ValueAnimator.ofInt(255, 0) 56 .setDuration(fadeOutDurationMs); 57 mFadeOutAnimator.addUpdateListener(new AnimatorUpdateListener() { 58 @Override 59 public void onAnimationUpdate(ValueAnimator animation) { 60 setAlpha((Integer) animation.getAnimatedValue()); 61 } 62 }); 63 64 reset(); 65 } 66 67 public void reset() { 68 setAlpha(0); 69 setVisible(false); 70 } 71 72 @Override 73 protected void onBoundsChange(Rect bounds) { 74 super.onBoundsChange(bounds); 75 76 if (mInner == null) { 77 return; 78 } 79 80 if (bounds.isEmpty()) { 81 mInner.setBounds(0, 0, 0, 0); 82 } else { 83 final int l = bounds.left + (bounds.width() / 2) - (mInnerWidth / 2); 84 final int t = bounds.top + (bounds.height() / 2) - (mInnerHeight / 2); 85 mInner.setBounds(l, t, l + mInnerWidth, t + mInnerHeight); 86 } 87 } 88 89 @Override 90 public void draw(Canvas canvas) { 91 if (!isVisible() && mPaint.getAlpha() == 0) { 92 return; 93 } 94 // Save paint alpha. 95 final int alpha = mPaint.getAlpha(); 96 mPaint.setColor(getColorWithAlpha(mOpts.backgroundColor, alpha)); 97 canvas.drawRect(getBounds(), mPaint); 98 // Restore paint alpha. 99 mPaint.setAlpha(alpha); 100 101 if (mInner != null) mInner.draw(canvas); 102 } 103 104 @Override 105 public void setAlpha(int alpha) { 106 final int old = mPaint.getAlpha(); 107 mPaint.setAlpha(alpha); 108 setInnerAlpha(alpha); 109 if (alpha != old) { 110 invalidateSelf(); 111 } 112 } 113 114 @Override 115 public void setColorFilter(ColorFilter cf) { 116 mPaint.setColorFilter(cf); 117 if (mInner != null) mInner.setColorFilter(cf); 118 } 119 120 @Override 121 public int getOpacity() { 122 return 0; 123 } 124 125 protected int getCurrentAlpha() { 126 return mPaint.getAlpha(); 127 } 128 129 public boolean setVisible(boolean visible) { 130 return setVisible(visible, true /* dontcare */); 131 } 132 133 @Override 134 public boolean setVisible(boolean visible, boolean restart) { 135 if (mInner != null) mInner.setVisible(visible, restart); 136 final boolean changed = super.setVisible(visible, restart); 137 if (changed) { 138 if (isVisible()) { 139 // pop in (no-op) 140 // the transition will still be smooth if the previous state's layer fades out 141 mFadeOutAnimator.cancel(); 142 setAlpha(255); 143 } else { 144 // fade out 145 if (mPaint.getAlpha() == 255 && !getBounds().isEmpty()) { 146 mFadeOutAnimator.start(); 147 } 148 } 149 } 150 return changed; 151 } 152 153 @Override 154 protected boolean onLevelChange(int level) { 155 if (mInner != null) 156 return mInner.setLevel(level); 157 else { 158 return super.onLevelChange(level); 159 } 160 } 161 162 /** 163 * Changes the alpha on just the inner wrapped drawable. 164 */ 165 public void setInnerAlpha(int alpha) { 166 if (mInner != null) mInner.setAlpha(alpha); 167 } 168 169 @Override 170 public void invalidateDrawable(Drawable who) { 171 invalidateSelf(); 172 } 173 174 @Override 175 public void scheduleDrawable(Drawable who, Runnable what, long when) { 176 scheduleSelf(what, when); 177 } 178 179 @Override 180 public void unscheduleDrawable(Drawable who, Runnable what) { 181 unscheduleSelf(what); 182 } 183 184 private static int getColorWithAlpha(int color, int alpha) { 185 float fade = alpha / 255f; 186 return Color.argb((int) (fade * Color.alpha(color)), Color.red(color), Color.green(color), 187 Color.blue(color)); 188 } 189} 190