自定义视图中的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 
    } 

} 
+0

你检查所有的XML文件在不同的文件夹?例如:layout-sw360dp –

+0

@LOG_TAG:是的,我已经完成了。如果其中一个布局资源文件中缺少'View',我会得到'NullPointerException',无论如何,对吧? – caw

+3

@MarcoW。我不确切知道这里发生了什么,但这不是setWillNotDraw的用途。它所做的只是告诉Android,它不需要为这个视图创建一个渲染列表:它只是建议。如果你想要这个工作,当你处于非绘制状态时,保持你自己的布尔状态并将onDraw短路。 –

几个小时的调试后,我终于找到了解决办法。

起初,我已将此添加到我的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); 
} 
+0

在那里的所有答案中,你是最有帮助的。 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(); 
} 
+0

谢谢!这并没有解决问题,但它改善了代码。 – caw