自定义视图中的Android 4.4不拉丝对于一些用户奇巧
我在Android上,这是显示没有在开始自定义View
类,但只有尽快绘制它的内容show()
已调用它。自定义视图中的Android 4.4不拉丝对于一些用户奇巧
我已经在Android 4.1和4.4上检查了它,它似乎工作。然而,一些使用Android KitKat的用户(例如三星Galaxy S4)报告说,在这个View
中没有任何东西可以绘制。这可能是什么原因? (The full code can be found here.)
用法在XML:Java中
<com.my.package.MyView
android:id="@+id/my_view"
android:layout_width="48dp"
android:layout_height="48dp" />
用法:
MyView myView = (MyView) findViewById(R.id.my_view);
myView.show(42);
引用的类MyView
在Java中:
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
}
}
几个小时的调试后,我终于找到了解决办法。
起初,我已将此添加到我的init()
方法(这是所有构造函数调用):
setWillNotDraw(false);
的Android绝知此事要View
必须被渲染和绘制,这应该是默认值,反正。但是,如果您扩展ViewGroup
,例如,它不是默认设置,所以您必须用来清除该标志。
正如其他人所指出的,人们只应该调用一次该方法,以便为View
设置正确的标志。如果您想在开始时防止绘图,请使用自定义标志,并且只在适当时执行onDraw(...)
中的语句。因此,我从show(...)
删除第二个电话setWillNotDraw(...)
。
除此之外,我加了一个电话......
invalidate();
...在show(...)
结束,这是当我对我的自定义View
提供输入,则必须重新绘制。
但是,View
未被绘制的问题(“不可见”View
)只在某些设备上发生。例如,它是三星Galaxy S4(Android 4.4)。当我在Android 4.4的模拟器上测试它时,问题没有发生。其原因竟是简单:
View.isHardwareAccelerated()
透露,银河S4(Android 4.4系统)用的定制View
硬件加速,而银河S3迷你(安卓4.1.2),银河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);
}
在那里的所有答案中,你是最有帮助的。 setLayerType方法为我做了! –
保持自己的布尔周围是否你应该是否绘图:
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();
}
谢谢!这并没有解决问题,但它改善了代码。 – caw
你检查所有的XML文件在不同的文件夹?例如:layout-sw360dp –
@LOG_TAG:是的,我已经完成了。如果其中一个布局资源文件中缺少'View',我会得到'NullPointerException',无论如何,对吧? – caw
@MarcoW。我不确切知道这里发生了什么,但这不是setWillNotDraw的用途。它所做的只是告诉Android,它不需要为这个视图创建一个渲染列表:它只是建议。如果你想要这个工作,当你处于非绘制状态时,保持你自己的布尔状态并将onDraw短路。 –