|
1 /* |
|
2 * Copyright (C) 2013 Square, Inc. |
|
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 package com.squareup.picasso; |
|
17 |
|
18 import android.content.Context; |
|
19 import android.content.res.Resources; |
|
20 import android.graphics.Bitmap; |
|
21 import android.graphics.Canvas; |
|
22 import android.graphics.ColorFilter; |
|
23 import android.graphics.Paint; |
|
24 import android.graphics.Path; |
|
25 import android.graphics.Point; |
|
26 import android.graphics.Rect; |
|
27 import android.graphics.drawable.AnimationDrawable; |
|
28 import android.graphics.drawable.BitmapDrawable; |
|
29 import android.graphics.drawable.Drawable; |
|
30 import android.os.SystemClock; |
|
31 import android.widget.ImageView; |
|
32 |
|
33 import static android.graphics.Color.WHITE; |
|
34 import static com.squareup.picasso.Picasso.LoadedFrom.MEMORY; |
|
35 |
|
36 final class PicassoDrawable extends Drawable { |
|
37 // Only accessed from main thread. |
|
38 private static final Paint DEBUG_PAINT = new Paint(); |
|
39 |
|
40 private static final float FADE_DURATION = 200f; //ms |
|
41 |
|
42 /** |
|
43 * Create or update the drawable on the target {@link ImageView} to display the supplied bitmap |
|
44 * image. |
|
45 */ |
|
46 static void setBitmap(ImageView target, Context context, Bitmap bitmap, |
|
47 Picasso.LoadedFrom loadedFrom, boolean noFade, boolean debugging) { |
|
48 Drawable placeholder = target.getDrawable(); |
|
49 if (placeholder instanceof AnimationDrawable) { |
|
50 ((AnimationDrawable) placeholder).stop(); |
|
51 } |
|
52 PicassoDrawable drawable = |
|
53 new PicassoDrawable(context, placeholder, bitmap, loadedFrom, noFade, debugging); |
|
54 target.setImageDrawable(drawable); |
|
55 } |
|
56 |
|
57 /** |
|
58 * Create or update the drawable on the target {@link ImageView} to display the supplied |
|
59 * placeholder image. |
|
60 */ |
|
61 static void setPlaceholder(ImageView target, int placeholderResId, Drawable placeholderDrawable) { |
|
62 if (placeholderResId != 0) { |
|
63 target.setImageResource(placeholderResId); |
|
64 } else { |
|
65 target.setImageDrawable(placeholderDrawable); |
|
66 } |
|
67 if (target.getDrawable() instanceof AnimationDrawable) { |
|
68 ((AnimationDrawable) target.getDrawable()).start(); |
|
69 } |
|
70 } |
|
71 |
|
72 private final boolean debugging; |
|
73 private final float density; |
|
74 private final Picasso.LoadedFrom loadedFrom; |
|
75 final BitmapDrawable image; |
|
76 |
|
77 Drawable placeholder; |
|
78 |
|
79 long startTimeMillis; |
|
80 boolean animating; |
|
81 int alpha = 0xFF; |
|
82 |
|
83 PicassoDrawable(Context context, Drawable placeholder, Bitmap bitmap, |
|
84 Picasso.LoadedFrom loadedFrom, boolean noFade, boolean debugging) { |
|
85 Resources res = context.getResources(); |
|
86 |
|
87 this.debugging = debugging; |
|
88 this.density = res.getDisplayMetrics().density; |
|
89 |
|
90 this.loadedFrom = loadedFrom; |
|
91 |
|
92 this.image = new BitmapDrawable(res, bitmap); |
|
93 |
|
94 boolean fade = loadedFrom != MEMORY && !noFade; |
|
95 if (fade) { |
|
96 this.placeholder = placeholder; |
|
97 animating = true; |
|
98 startTimeMillis = SystemClock.uptimeMillis(); |
|
99 } |
|
100 } |
|
101 |
|
102 @Override public void draw(Canvas canvas) { |
|
103 if (!animating) { |
|
104 image.draw(canvas); |
|
105 } else { |
|
106 float normalized = (SystemClock.uptimeMillis() - startTimeMillis) / FADE_DURATION; |
|
107 if (normalized >= 1f) { |
|
108 animating = false; |
|
109 placeholder = null; |
|
110 image.draw(canvas); |
|
111 } else { |
|
112 if (placeholder != null) { |
|
113 placeholder.draw(canvas); |
|
114 } |
|
115 |
|
116 int partialAlpha = (int) (alpha * normalized); |
|
117 image.setAlpha(partialAlpha); |
|
118 image.draw(canvas); |
|
119 image.setAlpha(alpha); |
|
120 invalidateSelf(); |
|
121 } |
|
122 } |
|
123 |
|
124 if (debugging) { |
|
125 drawDebugIndicator(canvas); |
|
126 } |
|
127 } |
|
128 |
|
129 @Override public int getIntrinsicWidth() { |
|
130 return image.getIntrinsicWidth(); |
|
131 } |
|
132 |
|
133 @Override public int getIntrinsicHeight() { |
|
134 return image.getIntrinsicHeight(); |
|
135 } |
|
136 |
|
137 @Override public void setAlpha(int alpha) { |
|
138 this.alpha = alpha; |
|
139 if (placeholder != null) { |
|
140 placeholder.setAlpha(alpha); |
|
141 } |
|
142 image.setAlpha(alpha); |
|
143 } |
|
144 |
|
145 @Override public void setColorFilter(ColorFilter cf) { |
|
146 if (placeholder != null) { |
|
147 placeholder.setColorFilter(cf); |
|
148 } |
|
149 image.setColorFilter(cf); |
|
150 } |
|
151 |
|
152 @Override public int getOpacity() { |
|
153 return image.getOpacity(); |
|
154 } |
|
155 |
|
156 @Override protected void onBoundsChange(Rect bounds) { |
|
157 super.onBoundsChange(bounds); |
|
158 |
|
159 image.setBounds(bounds); |
|
160 if (placeholder != null) { |
|
161 placeholder.setBounds(bounds); |
|
162 } |
|
163 } |
|
164 |
|
165 private void drawDebugIndicator(Canvas canvas) { |
|
166 DEBUG_PAINT.setColor(WHITE); |
|
167 Path path = getTrianglePath(new Point(0, 0), (int) (16 * density)); |
|
168 canvas.drawPath(path, DEBUG_PAINT); |
|
169 |
|
170 DEBUG_PAINT.setColor(loadedFrom.debugColor); |
|
171 path = getTrianglePath(new Point(0, 0), (int) (15 * density)); |
|
172 canvas.drawPath(path, DEBUG_PAINT); |
|
173 } |
|
174 |
|
175 private static Path getTrianglePath(Point p1, int width) { |
|
176 Point p2 = new Point(p1.x + width, p1.y); |
|
177 Point p3 = new Point(p1.x, p1.y + width); |
|
178 |
|
179 Path path = new Path(); |
|
180 path.moveTo(p1.x, p1.y); |
|
181 path.lineTo(p2.x, p2.y); |
|
182 path.lineTo(p3.x, p3.y); |
|
183 |
|
184 return path; |
|
185 } |
|
186 } |