Canvas not displaying all drawn parts in Custom View?

让人想犯罪 __ 提交于 2019-11-28 06:37:18

So, the key clue in my mystery seemed to be that it worked on the emulator, but not on the hardware devices.

Hardware Rendering

I did peruse the hardware rendering page on the Android Developer's website, but apparently not closely enough.

http://developer.android.com/guide/topics/graphics/hardware-accel.html

While it does mention that the API's are available beginning version 11, it does not say that Hardware Rendering is turned on for all applications by default, starting with API Level 14 (ICS).

What does this mean for us?

Almost everything is faster; except for the few things that don't work.

I managed to violate two of these, without realizing it:

  • Canvas.DrawTextOnPath()
  • Paint.setShadowLayer()

It's not mentioned in the API reference (or anywhere else I can find, and certainly not checked by Lint), but using any of the listed operations can do weird things.

In my case, Canvas.DrawTextOnPath() seemed to work just fine.

But when Android notice that the paint that I used on the hand had shadow layer set, it silently ignored it.

How do I know if my View is hardware accelerated?

From the documentation link above:

There are two different ways to check whether the application is hardware accelerated:

  • View.isHardwareAccelerated() returns true if the View is attached to a hardware accelerated window.
  • Canvas.isHardwareAccelerated() returns true if the Canvas is hardware accelerated

If you must do this check in your drawing code, use Canvas.isHardwareAccelerated() instead >of View.isHardwareAccelerated() when possible. When a view is attached to a hardware >accelerated window, it can still be drawn using a non-hardware accelerated Canvas. This >happens, for instance, when drawing a view into a bitmap for caching purposes.

In my case, the opposite appears to have occurred. The custom view logs that it is not Hardware-accelerated; however, the canvas reports that it is hardware-accelerated.

Work Arounds and Fixings

The simplest fix is forcing the custom view to do software rendering. Per the documentation this can be accomplished by:

myView.setLayerType(View.LAYER_TYPE_SOFTWARE, null);

Alternatively, you could remove the offending operations, and keep hardware rendering turned on.

Learn from my misfortune. Good luck, all.

I put it into init() and worked fine after that.

    private void init() {
    setLayerType(myView.LAYER_TYPE_SOFTWARE, null);
    ....
}

Eagle, where exactly do you call this line? I call it after initialising:

    tachometer = (CustomRoundInstrument) theFragment.findViewById(R.id.tachometer);
    tachometer.setLayerType(View.LAYER_TYPE_SOFTWARE, null);

Thatdoes not work though, do I have to call it some place else?

Help is appreciated!

With myView.setLayerType(View.LAYER_TYPE_SOFTWARE, null); suggestion I can see hand. But I have still a problem: I see scale with only 0 written! As in the picture and two strage zeros out of the schema: (GALAXY NEXUS 4.2.1)

My drawScale() method is as in the example:

 private void drawScale(Canvas canvas) {
        canvas.drawOval(scaleRect, scalePaint);

        canvas.save(Canvas.MATRIX_SAVE_FLAG);
        for (int i = 0; i < totalNicks; ++i) {
            float y1 = scaleRect.top;
            float y2 = y1 - 0.020f;

            canvas.drawLine(0.5f, y1, 0.5f, y2, scalePaint);


            if ((i % 5) == 0) {
                int value = nickToDegree(i);

                if ((value >= minDegrees) && (value <= maxDegrees)) {
                    String valueString = Integer.toString(value);
                    canvas.drawText(valueString, 0.5f, y2 - 0.015f, scalePaint);

                }
            }

            canvas.rotate(degreesPerNick, 0.5f, 0.5f);


        }
        canvas.restore();

    }

in my case i made this:

 AnalogView bar = (AnalogView) findViewById(R.id.AnalogBar);
    bar.setLayerType(bar.LAYER_TYPE_SOFTWARE, null);
if (value_list.size()>0)   bar.SetData(Double.parseDouble(value_list.get(value_list.size()-1)));

where SetData in AnalogView is

public  void SetData(double data) {
    setHandTarget((float)data);
  invalidate();
}
Ben LeDuc

On Galaxy S4 Android 4.4.2

TYPE_TEMPERATURE is deprecated

use

TYPE_AMBIENT_TEMPERATURE

For anyone having problems with text drawing on scale in the initialisation do this:

scalePaint.setLinearText(true);

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!