16

たくさんの画像に線を引くアプリを開発しています。これらの画像を選択するために、ラジオ グループがあり、ユーザーがラジオ ボタンをクリックするたびに、画像がすべての独自の図面と共に読み込まれます。

私のラジオリスナーには、次のコードがあります。

bitmap = BitmapUtils.decodeSampledBitmapFromResource(root + DefinesAndroid.CAMINHO_SHOPPINGS_SDCARD + nomeImagemAtual, size.x, size.y);
mImage.setImageBitmap(bitmap);

mImage.setDrawLines(true);
mImage.setImageBitmap(loadBitmapFromView(mImage));

Android開発者のこのリンクから得たdecodeSampledBitmapFromResource方法(ビットマップをより効率的にロードします)http://developer.android.com/training/displaying-bitmaps/load-bitmap.html

ビューのビットマップを取得するために呼び出すメソッドは次のとおりです。

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

ImageViewTouchライブラリ(ImageViewのピンチズームを可能にする)を使用しているため、画像のビットマップを設定してmImageいます。これを行わないと、画像に対する操作(ズームイン/ズームなど)ですべてのキャンバス描画が削除されますアウト)。

エラーログは以下

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)

getBitmapFromViewメソッドを呼び出したときに画像ビットマップが完全に読み込まれていないため、このエラーが発生しているとほぼ確信しています。

ビューが完全にロードされたことを知るにはどうすればよいですか?

4

3 に答える 3

28

次のように呼び出しloadBitmapFromViewます。

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

Runnablepost()メソッドに指定された は、ビューの測定とレイアウトの後に実行されるため、getWidth()実際getHeight()の幅と高さを返します。

他にできることは、Viewを呼び出して手動で測定し、とmeasureから結果を取得することです。しかし、私はこの方法をお勧めしません。getMeasuredWidth()getMeasuredHeight()

于 2013-07-18T20:34:48.073 に答える
17

実際には、 を使用してそれを行う別のより信頼できる方法がありますViewTreeObserver.OnPreDrawListener。そして、ここに例があります:

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

すべてのビューがすでに測定およびレイアウトされている可能性が最も高い場合にのみ実行しながら、測定およびレイアウトされたOnPreDrawListener 保証を使用します。ViewView#post(Runnable)Runnable

于 2014-01-21T08:54:43.997 に答える
1

以下は、上記の Dmitry のメソッドを組み込み、ImageView が実際に使用可能になった後にのみ通知するコードを追加する、動作中の NotifyImageView クラスです。

お役に立てば幸いです。

`

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

        }
    }

}

`

于 2015-09-30T20:49:59.967 に答える