Android 4.4 KitKat中的某些用户没有自定义视图

时间:2014-03-28 23:28:33

标签: android android-view

我在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
    }

}

2 个答案:

答案 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();
}