Difference between drawing directly on canvas and drawing on a bitmap and then canvas in Android onDraw ()

I am writing a custom view that displays signals. To shorten the onDraw () time, I cache everything I have done so far in Bitmap, and just add onDraw () to it every time. By doing this, I can save a huge amount of time, since I only need to draw a few corrections at a time, and not redo it all.

There are things that bother me - it seems that drawing directly on the provided canvas provides a more β€œaccurate” drawing than drawing on a bitmap and then drawing a bitmap on canvas. By looking at the bottom of the following figure, you can see the difference:

Look at the lower part of the signal to see difference - there are the same drawLine calls

I downloaded a demo project displaying a mismatch on https://github.com/gardarh/android-uglybitmapdrawing/ , but the corresponding code looks like this:

@Override public void onDraw(Canvas canvas) { if(cachedBitmap == null) { cachedBitmap = Bitmap.createBitmap(getWidth(), 200, Config.ARGB_8888); cachedCanvas = new Canvas(cachedBitmap); } for(int i = 0; i < COORDS.length; i++) { float[] curCoords = COORDS[i]; canvas.drawLine(curCoords[0], curCoords[1], curCoords[2], curCoords[3], linePaint); cachedCanvas.drawLine(curCoords[0], curCoords[1], curCoords[2], curCoords[3], linePaint); } canvas.drawBitmap(cachedBitmap, 0, 120, null); } 

Why don't the two tracks match and, more importantly, how can I make the bottom trace look like the top one?

+4
source share
3 answers

The reason for the differences is that the canvas is drawn using hardware acceleration (GPU), and the bitmap is drawn using software (CPU). If you disable hardware acceleration, they will become exactly the same. If you multiply the X-coordinates by 10, you will see that the difference is in how the lines connect. This is a slight difference in one pixel, and I would not bother with them. I'm not sure which one is more accurate, they just seem like slightly different implementations.

+2
source

The Android framework API provides 2D drawing APIs for simple animations that do not require significant dynamic changes. There are two implementation methods using this API.

1. Drawing to view 2. Drawing on canvas

1.Select a circle to view

Drawing for viewing is the best option when your user interface does not require dynamic changes in the application. This can be achieved by simply extending the View class and defining the onDraw () callback method.
Use the Canvas provided to you for your entire drawing,
using various methods of Canvas.draw ... () (Example: canvas.drawCircle (x / 2, y / 2, radius, paint);). onDraw () is a callback method that is called when the view is first drawn.

The following is a simple code example for drawing a circle: -

MainActivity.java

  public class MainActivity extends Activity { @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(new MyView(this)); } public class MyView extends View { public MyView(Context context) { super(context); // TODO Auto-generated constructor stub } @Override protected void onDraw(Canvas canvas) { // TODO Auto-generated method stub super.onDraw(canvas); int x = getWidth(); int y = getHeight(); int radius; radius = 100; Paint paint = new Paint(); paint.setStyle(Paint.Style.FILL); paint.setColor(Color.WHITE); canvas.drawPaint(paint); // Use Color.parseColor to define HTML colors paint.setColor(Color.parseColor("#FB9J2F")); canvas.drawCircle(x / 2, y / 2, radius, paint); } } } 

2. Drawing a rectangle on canvas

To draw dynamic 2D graphics, where you need to draw yourself regularly in your application, drawing on canvas is the best option. The canvas works for you as an interface, on the actual surface on which your graphics will be drawn.

If you need to create a new canvas, you must define a bitmap on which the actual drawing will be performed. A bitmap is always required for a canvas. The following example explains how to draw a rectangle: -

activity_main.xml

 <?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:orientation="vertical" android:layout_width="match_parent" android:layout_height="match_parent" android:id="@+id/mylayout"> </LinearLayout> 

MainActivity.java

 public class MainActivity extends Activity { @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); Paint paint = new Paint(); paint.setColor(Color.parseColor("#DD4N5C")); Bitmap bitmap = Bitmap.createBitmap(512, 800, Bitmap.Config.ARGB_8888); Canvas canvas = new Canvas(bitmap); canvas.drawRect(150, 150, 250, 250, paint); LinearLayout layout = (LinearLayout) findViewById(R.id.mylayout); layout.setBackgroundDrawable(new BitmapDrawable(bitmap)); } } 
+3
source

I do not agree that you save a lot by going along the raster route. You can consider a data structure that stores the return signal and converts it into a JSON object that can be serialized / deserialized. As for your question, this is a reasonable assumption, but it is more related to changing the return signal, since you do not use getHeight () when creating a bitmap image.

0
source

Source: https://habr.com/ru/post/1485439/


All Articles