質問

I'm having a problem rendering a long TextView in a hardware accelerated activity (android:hardwareAccelerated="true"). The textview has no background color (i.e. it is transparent). When the text is longer than a certain length, the textview renders with a solid black background instead of a transparent background.

The text in the TextView can be edited by the user, and is being forced to not wrap except at actual newlines. I'm doing this by calculating the width of the text like so:

int textWidth = 0;
String[] lines = string.split("\\n");
for (String line : lines) {
    int lineWidth = (int) tv.getPaint().measureText(line);
    if (lineWidth > textWidth) {
        textWidth = lineWidth;
    }
}
int width = m.getPaddingLeft() + tv.getPaddingLeft() + textWidth
            + tv.getPaddingRight() + m.getPaddingRight();

Then I Override the onMeasure method of the ViewGroup to force the width to be at least as long as the text:

@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
    super.onMeasure(widthMeasureSpec, heightMeasureSpec);
    int newWidth = Math.max(getMeasuredWidth(), width);
    setMeasuredDimension(newWidth, getMeasuredHeight());
}

All of this is working as expected, but it allows the text to get really big - too big apparently.

Attempted Solutions: I guessed that the problem was with OpenGL being unable to render something that long, so I queried the GL_MAX_TEXTURE_SIZE OpenGL parameter and compared it to the width. Sure enough, the problem occurs when width > GL_MAX_TEXTURE_SIZE.

To solve this problem, I wrote some code to disable hardware acceleration on the view when the text is too long:

int[] maxGlTexSize = new int[1];
GLES20.glGetIntegerv(GLES20.GL_MAX_TEXTURE_SIZE, maxGlTexSize, 0);
if (width > maxGlTexSize[0]) {
    Log.e("Debug", "Too big for GL");
    tv.setLayerType(View.LAYER_TYPE_SOFTWARE, null);
} else {
    Log.i("Debug", "Small enough for GL");
    tv.setLayerType(View.LAYER_TYPE_NONE, null);
}

However, this code doesn't work for me. When the condition is met (the text is too long), the textview becomes invisible. This also happens if I try to use LAYER_TYPE_HARDWARE. (I tried that because the Hardware Acceleration guide says to set the layer type to HARDWARE for large views with alpha.)

Also, I did try permanently setting the view layer type. The results were slightly different for the two types:

  • LAYER_TYPE_SOFTWARE: When the activity is created with text smaller than the limit, it renders fine. When text is added to surpass the limit, the view disappears. When the text is shortened to be within the limit again, it reappears.

  • LAYER_TYPE_HARDWARE: Identical to LAYER_TYPE_SOFTWARE except that the text does not reappear when shortened after being too long. The activity must be recreated in order for the text to reappear.

TL;DR

I'm having a view rendering problem caused by OpenGL limitations, but view.setLayerType(View.LAYER_TYPE_SOFTWARE, null); is making the view disappear rather than fixing the problem.

役に立ちましたか?

解決

After thinking about this problem for a bit, I realized that it makes sense that changing the layer type of the view doesn't solve the problem. If the activity is hardware accelerated, the view still has to be stored in a GPU texture to be rendered to the screen, regardless of whether or not the view is hardware accelerated.

To solve the problem, I simply lowered the resolution (size) of the text until the view's width was less than the GL_MAX_TEXTURE_SIZE. This works well because the text doesn't need to be high resolution if the user is displaying a lot of it, because they will scale it down to fit all of the text on the screen.

ライセンス: CC-BY-SA帰属
所属していません StackOverflow
scroll top