I'm writing a custom view that displays signals. In order to shorten my onDraw() time I cache everything I've drawn so far in a Bitmap and just append to that in every onDraw() call. By doing this I can save huge amounts of time since I only need to draw a few fixels at a time instead of redoing the whole thing.
There is on thing bothering me though - it appears as drawing directly to the provided canvas provides a more "accurate" drawing than drawing on the bitmap first and then drawing the bitmap on the canvas. By looking at the lower part of the following picture you can see the difference:
I uploaded a demo project displaying the discrepancy at https://github.com/gardarh/android-uglybitmapdrawing/ but the relevant code is as follows:
@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 are the two traces not the same and more importantly, how can I make the lower trace look like the upper one?
Canvas is the place or medium where perfroms/executes the operation of drawing, and Bitmap is responsible for storing the pixel of the picture you draw.
Override onDraw() The parameter to onDraw() is a Canvas object that the view can use to draw itself. The Canvas class defines methods for drawing text, lines, bitmaps, and many other graphics primitives. You can use these methods in onDraw() to create your custom user interface (UI).
Canvas API is a drawing framework that is provided in Android, with the help of which we can create custom shapes like rectangle, circle, and many more in our UI design. With the help of this API, we can draw any type of shape for our app. The drawing of the different shapes is done using Bitmap.
The reason for the differences is that the canvas drawing is done by hardware acceleration (GPU), and the bitmap drawing is done by software (CPU). If you disable hardware acceleration, they become the exact same. If you multiply the X coordinates by 10, you will see that the difference is in the way lines are joined. These are minor one pixel difference and I wouldn't bother with them. I am not sure which one is the more accurate, they seem like just slightly different implementations.
Android framework API provides 2D drawing APIs for simple animation that does not require major dynamic changes. There are two ways of implementation using these API.
1. Drawing to a View
2. Drawing on a Canvas
1.Drawing a circle to View
Drawing to view is a better option when your UI does not require dynamic changes in the application.
This can be achieved simply by extending the View class and define an onDraw() callback method.
Use the Canvas given to you for all your drawing,
using various Canvas.draw...() methods (Ex: canvas.drawCircle(x / 2, y / 2, radius, paint);). onDraw() is a callback method invoked when the view is initially drawn.
Below is a simple example code to draw 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 rectangle on a canvas
To draw dynamic 2D graphics where in your application needs to regularly re draw itself, drawing on a canvas is a better option. A Canvas works for you as an interface, to the actual surface upon which your graphics will be drawn.
If you need to create a new Canvas, then you must define the bitmap upon which drawing will actually be performed. The Bitmap is always required for a Canvas.
The below example explains 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));
}
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With