'How to get when an ImageView is completely loaded in Android
I'm developing an App which draws lines over a bunch of Images. To choose these images, I have a radio group and, whenever the user clicks in a radio button, the image is load with all its own drawings.
In my radio listenner I have the following code:
bitmap = BitmapUtils.decodeSampledBitmapFromResource(root + DefinesAndroid.CAMINHO_SHOPPINGS_SDCARD + nomeImagemAtual, size.x, size.y);
mImage.setImageBitmap(bitmap);
mImage.setDrawLines(true);
mImage.setImageBitmap(loadBitmapFromView(mImage));
the decodeSampledBitmapFromResource method I got from this link on android developers (it loads bitmaps more effitiently) http://developer.android.com/training/displaying-bitmaps/load-bitmap.html
And here's the method I call to get a Bitmap of a View
public static Bitmap loadBitmapFromView(View v) {
Bitmap b = Bitmap.createBitmap( v.getLayoutParams().width, v.getLayoutParams().height, Bitmap.Config.ARGB_8888);
Canvas c = new Canvas(b);
v.layout(0, 0, v.getLayoutParams().width, v.getLayoutParams().height);
v.draw(c);
return b;
}
I'm setting the image Bitmap of mImage because I'm using ImageViewTouch library (which enables pinch zooming over an ImageView) and if I don't do it, all the canvas drawing is deleted with any interaction over the image (like zooming in/out).
The error log is the following
07-11 21:13:41.567: E/AndroidRuntime(20056): java.lang.IllegalArgumentException: width and height must be > 0
07-11 21:13:41.567: E/AndroidRuntime(20056): at android.graphics.Bitmap.createBitmap(Bitmap.java:638)
07-11 21:13:41.567: E/AndroidRuntime(20056): at android.graphics.Bitmap.createBitmap(Bitmap.java:620)
I'm almost sure that this error is occuring cause the image bitmap is not completely loaded when I call getBitmapFromView method.
How can I know when the view is loaded completely?
Solution 1:[1]
There is actually another, more reliable way to do that by using ViewTreeObserver.OnPreDrawListener. And here is an example:
mImage.getViewTreeObserver().addOnPreDrawListener(new ViewTreeObserver.OnPreDrawListener() {
@Override
public boolean onPreDraw() {
try {
loadBitmapFromView(mImage);
// Note that returning "true" is important,
// since you don't want the drawing pass to be canceled
return true;
} finally {
// Remove listener as further notifications are not needed
mImage.getViewTreeObserver().removeOnPreDrawListener(this);
}
}
});
Using OnPreDrawListener guarantees that View was measured and layouted, while View#post(Runnable) just executes your Runnable when all Views are already most likely measured and layouted.
Solution 2:[2]
Below is a working NotifyImageView class that incorporates Dmitry's method above and adds code to notify only after the ImageView is truly usable.
I hope you find it useful.
`
public interface NotifyImageHolder {
public void notifyImageChanged(final NotifyImageView thePosterImage, final int width, final int height);
}
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.drawable.Drawable;
import android.util.AttributeSet;
import android.view.ViewTreeObserver;
import android.widget.ImageView;
public class NotifyImageView extends ImageView {
private boolean mImageChanged;
private NotifyImageHolder mHolder;
private boolean mImageFinished;
public NotifyImageView(Context context) {
super(context);
init();
}
public NotifyImageView(Context context, AttributeSet attrs) {
super(context, attrs);
init();
}
public NotifyImageView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
init();
}
protected void init() {
mImageChanged = false;
mImageFinished = false;
mHolder = null;
monitorPreDraw();
}
// so we can tell when the image finishes loading..
protected void monitorPreDraw() {
final NotifyImageView thePosterImage = this;
getViewTreeObserver().addOnPreDrawListener(new ViewTreeObserver.OnPreDrawListener() {
@Override
public boolean onPreDraw() {
try {
return true; //note, that "true" is important, since you don't want drawing pass to be canceled
} finally {
getViewTreeObserver().removeOnPreDrawListener(this); // we don't need any further notifications
thePosterImage.buildDrawingCache();
mImageFinished = true;
}
}
});
}
public void setNotifyImageHolder(NotifyImageHolder holder) {
this.mHolder = holder;
}
public boolean isImageChanged() {
return mImageChanged;
}
public boolean isImageFinished() {
return mImageFinished;
}
public void notifyOff() {
mHolder = null;
}
// the change notify happens here..
@Override
public void setImageDrawable(Drawable noPosterImage) {
super.setImageDrawable(noPosterImage);
if (mHolder != null && mImageFinished) {
mImageFinished = false; // we send a single change-notification only
final NotifyImageView theNotifyImageView = this;
theNotifyImageView.post(new Runnable() {
@Override
public void run() {
if (mHolder != null) {
int width = getMeasuredWidth();
int height = getMeasuredHeight();
mImageChanged = true;
mHolder.notifyImageChanged(theNotifyImageView, width, height);
}
}
});
}
}
}
`
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
| Solution | Source |
|---|---|
| Solution 1 | Derek Lee |
| Solution 2 | Lee Hounshell |
