Keywords: Android Canvas | Circle Drawing | Custom View
Abstract: This article provides an in-depth analysis of the core mechanisms for drawing circles using Canvas in Android, explaining the root causes of black screen issues in the original code and presenting correct implementation based on the onDraw method. Starting from Canvas drawing principles, it systematically explains the drawing process of custom views, compares differences between incorrect and correct implementations, and helps developers deeply understand the operation mechanism of Android's graphics system.
Canvas Drawing Mechanism and Common Issue Analysis
In Android development, Canvas serves as the fundamental component for graphics drawing, and its correct usage is crucial for implementing custom views. The black screen issue in the original code stems from misunderstandings about Canvas lifecycle and drawing timing.
Original Code Problem Diagnosis
The user's code directly creates a Canvas object and performs drawing operations in the View constructor. This implementation approach has the following core issues:
First, the Canvas created in the constructor is separate from the Canvas actually used by the view system. The Android view system automatically creates Canvas objects when drawing is needed and passes them to views through the onDraw method. The manually created Canvas in the constructor only exists in memory and won't be displayed on screen.
Second, improper drawing timing. The view constructor executes when the view is created, but at this point the view hasn't been added to the window manager and lacks a valid drawing surface. Correct drawing should occur when the system calls the onDraw method.
Problematic implementation from the code example:
public class View extends SurfaceView {
public View(Context context, int w, int h) {
super(context);
Canvas grid = new Canvas(Bitmap.createBitmap(h,w, Bitmap.Config.ARGB_8888));
grid.drawColor(Color.WHITE);
Paint paint = new Paint();
paint.setStyle(Paint.Style.FILL);
grid.drawCircle(w/2, h/2, w/2, paint);
}
}Correct Implementation Solution
Based on the design principles of the Android view system, the correct implementation should override the onDraw method. This method is automatically called by the system when the view needs redrawing, ensuring drawing operations execute at the proper timing.
Basic implementation code:
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
Paint paint = new Paint();
paint.setStyle(Paint.Style.FILL);
paint.setColor(Color.RED);
int centerX = getWidth() / 2;
int centerY = getHeight() / 2;
int radius = Math.min(centerX, centerY);
canvas.drawCircle(centerX, centerY, radius, paint);
}Detailed Drawing Process
The drawing process of the Android view system follows a strict sequence:
1. Measurement phase (measure): Determines view dimensions
2. Layout phase (layout): Determines view positions
3. Drawing phase (draw): Calls onDraw method for actual drawing
Only during the drawing phase does the system provide a valid Canvas object. Any drawing operations performed in the constructor or onCreate method won't be reflected on screen.
Advanced Drawing Techniques
Beyond basic circle drawing, more complex drawing effects can be achieved through Canvas transformations. For example, using the translate method to move the canvas to the center point:
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
canvas.translate(getWidth()/2f, getHeight()/2f);
Paint paint = new Paint();
paint.setStyle(Paint.Style.FILL);
paint.setColor(Color.BLUE);
canvas.drawCircle(0, 0, 100, paint);
}This approach simplifies coordinate calculations and is particularly suitable for complex graphics drawing that uses the view center as reference.
Performance Optimization Recommendations
In practical development, frequent object creation in the onDraw method should be avoided. It's recommended to initialize Paint objects as member variables:
public class MyView extends View {
private Paint circlePaint;
public MyView(Context context) {
super(context);
init();
}
private void init() {
circlePaint = new Paint();
circlePaint.setStyle(Paint.Style.FILL);
circlePaint.setColor(Color.GREEN);
circlePaint.setAntiAlias(true);
}
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
canvas.drawCircle(getWidth()/2, getHeight()/2, 100, circlePaint);
}
}Object reuse reduces GC pressure and improves drawing performance.