我在Android中有一个自定义View
类,它在开头显示 nothing ,但只有在show()
被调用时才会显示其内容
我已经在Android 4.1和4.4上检查了这一点,它似乎有效。但是,一些使用Android KitKat的用户(例如在三星Galaxy S4上)报告说,View
中没有任何内容。可能是什么原因? (The full code can be found here.)
XML中的用法:
<com.my.package.MyView
android:id="@+id/my_view"
android:layout_width="48dp"
android:layout_height="48dp" />
Java中的用法:
MyView myView = (MyView) findViewById(R.id.my_view);
myView.show(42);
Java中引用的类MyView
:
public class MyView extends View {
public MyView(Context context) {
super(context);
init();
}
public MyView(Context context, AttributeSet attrs) {
super(context, attrs);
init();
}
public MyView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
init();
}
protected void init() {
setWillNotDraw(true);
}
public void show(int input) {
// do some initialization so that onDraw() knows what to draw
setWillNotDraw(false);
// invalidate() doesn't seem to be necessary (no effect)
}
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
// draw things on the canvas now
}
}
答案 0 :(得分:3)
经过几个小时的调试后,我终于找到了解决方案。
首先,我将此添加到我的init()
方法(从所有构造函数调用)中:
setWillNotDraw(false);
Android必须知道必须渲染和绘制此View
,无论如何都应该是默认值。但是,如果您扩展ViewGroup
,例如,它不是默认设置,那么您有来清除该标志。
正如其他人所说,只应该调用该方法一次,以便为View
设置正确的标记。如果您想在开头阻止绘图,请使用自定义标记,并仅在适当时执行onDraw(...)
中的语句。因此,我从setWillNotDraw(...)
删除了对show(...)
的第二次调用。
除此之外,我还加了一个电话......
invalidate();
... show(...)
的末尾,即我向自定义View
提供输入时,必须重新绘制。
但是,View
未被绘制(“不可见”View
)的问题仅发生在某些设备上。例如,它是三星Galaxy S4(Android 4.4)。当我在使用Android 4.4的模拟器上测试它时,问题没有发生。原因很简单:
View.isHardwareAccelerated()
透露Galaxy S4(Android 4.4)在自定义View
上使用硬件加速,而Galaxy S3 Mini(Android 4.1.2),Galaxy S2和模拟器不是。
这是关于硬件加速的what the docs say:
所有2D绘图操作都不支持硬件加速,打开它可能会影响某些自定义视图或绘图调用。问题通常表现为不可见的元素,异常或错误渲染的像素。
除此之外,the GPU can cache your custom View
as a static image。
因此,简单的解决方案(在init()
中)禁用了自定义View
类的硬件加速:
if (Build.VERSION.SDK_INT >= 11) {
setLayerType(View.LAYER_TYPE_SOFTWARE, null);
}
答案 1 :(得分:0)
保持自己的布尔值,无论你是否应该画画:
private boolean mDraw;
protected void init() {
mDraw = false;
}
public void show(int input) {
mDraw = true;
invalidate();
}
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
if(!mDraw) return;
// draw things on the canvas now
}
或者,在实际需要时使用setVisibility:
protected void init() {
setVisibility(View.INVISIBLE);
}
public void show(int input) {
setVisibility(View.VISIBLE);
invalidate();
}