我正在开发一个应用程序,它在一堆图像上绘制线条。要选择这些图像,我有一个广播组,每当用户点击一个单选按钮时,图像就会加载所有图纸。
在我的电台听众中,我有以下代码:
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;
}
我正在设置mImage
的图像位图,因为我正在使用ImageViewTouch库(可以对ImageView进行缩放缩放),如果我不这样做,所有画布绘图都会被删除,并且会进行任何交互在图像上(如放大/缩小)。
错误日志如下
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
方法时,图像位图没有完全加载。
如何知道视图何时完全加载?
答案 0 :(得分:23)
以这种方式致电loadBitmapFromView
:
mImage.post(new Runnable() {
@Override
public void run() {
loadBitmapFromView(mImage);
}
});
提供给Runnable
方法的 post()
将在视图测量和布局后执行,因此getWidth()
和getHeight()
将返回实际的宽度和高度。
您还可以做什么,手动衡量View
,调用measure
,然后从getMeasuredWidth()
和getMeasuredHeight()
获取结果。但我不建议这样做。
答案 1 :(得分:11)
使用ViewTreeObserver.OnPreDrawListener
实际上有另一种更可靠的方法。这是一个例子:
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
}
}
});
使用OnPreDrawListener
保证 View
已经过测量和布局,而View#post(Runnable)
只在所有视图已经时执行Runnable
最有可能测量和布置。
答案 2 :(得分:1)
下面是一个工作的NotifyImageView类,它包含了上面的Dmitry方法 并添加代码以便在ImageView真正可用后才通知。
我希望你觉得它很有用。
`
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);
}
}
});
}
}
}
`