How to get when an ImageView is completely loaded in Android

天涯浪子 提交于 2019-12-04 00:25:35

问题


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?


回答1:


Call loadBitmapFromView in a such way:

mImage.post(new Runnable() {
    @Override
    public void run() {
        loadBitmapFromView(mImage);
    }
});

Runnable provided to post() method will be executed after view measuring and layouting, so getWidth() and getHeight() will return actual width and height.

What else can you do, is measuring View manually, by invoking measure, and then taking result from getMeasuredWidth() and getMeasuredHeight(). But I do not recommend this way.




回答2:


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);            
            return true;    //note, that "true" is important, since you don't want drawing pass to be canceled
        } finally {
            mImage.getViewTreeObserver().removeOnPreDrawListener(this);    //we don't need any further notifications
        }
    }
});

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.




回答3:


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);
                    }
                }
            });

        }
    }

}

`



来源:https://stackoverflow.com/questions/17606140/how-to-get-when-an-imageview-is-completely-loaded-in-android

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!