Как рисовать в custom View: Canvas, Paint и отладка
Для рисования в custom View переопределите onDraw(Canvas), заранее инициализируйте Paint в конструкторе/init(), используйте Canvas.draw* (circle, line, path, text, bitmap) и для анимации вызывайте postInvalidateOnAnimation() или invalidate(Rect) для частичной перерисовки — так вы получите корректную, быструю и отлаживаемую отрисовку.
Основы Canvas и Paint
Canvas — холст; Paint — кисть с настройками (цвет, ширина, стиль, шейдеры, сглаживание).
- Создайте View и инициализируйте ресурсы один раз:
public class MyView extends View {
private Paint paint;
public MyView(Context ctx) {
super(ctx);
init();
}
private void init() {
paint = new Paint(Paint.ANTI_ALIAS_FLAG);
paint.setColor(Color.RED);
paint.setStyle(Paint.Style.FILL);
paint.setStrokeWidth(4f);
}
@Override protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
canvas.drawCircle(100, 100, 50, paint);
}
}
- Частые методы Canvas: drawLine, drawRect, drawCircle, drawPath, drawText, drawBitmap.
- Path для сложных фигур:
Path p = new Path();
p.moveTo(50,50);
p.lineTo(150,50);
p.lineTo(100,150);
p.close();
canvas.drawPath(p, paint);
- Градиенты и эффекты: Shader (LinearGradient, RadialGradient) через paint.setShader(...). Для заливки фигур используйте Paint.Style.FILL, для обводки — STROKE.
Инициализируйте Paint, Path и Bitmap в init/конструкторе. Создание объектов в onDraw сильно снижает производительность.
Интерактив и анимация
- Обработка касаний: переопределите onTouchEvent, сохраняйте координаты или Path и вызывайте invalidate() для перерисовки.
@Override public boolean onTouchEvent(MotionEvent e) {
if (e.getAction() == MotionEvent.ACTION_DOWN || e.getAction() == MotionEvent.ACTION_MOVE) {
path.lineTo(e.getX(), e.getY());
invalidate(); // либо invalidate(dirtyRect)
}
return true;
}
- Анимация: используйте postInvalidateOnAnimation() или Choreographer для 60 FPS; избегайте таймеров с частыми invalidate без синхронизации.
// пример простого шага анимации
void step() {
updateState();
postInvalidateOnAnimation();
}
- Для частичной перерисовки передавайте область: invalidate(left, top, right, bottom) или invalidate(Rect), это экономит CPU/GPU.
- Аппаратное/программное рендеринг: при проблемах с некоторыми эффектами попробуйте setLayerType(LAYER_TYPE_SOFTWARE, paint) или наоборот — аппаратное ускорение обычно быстрее.
Отладка и оптимизация отрисовки
- Логируйте вызовы onDraw для понимa частоты:
Log.d("DRAW", "onDraw at " + System.currentTimeMillis());
- Profile GPU Rendering (включается в Developer Options) показывает, где узкие места.
- Layout Inspector/Hierarchy Viewer в Android Studio помогают увидеть сложную иерархию View и FPS.
- Советы по оптимизации:
- Минимизируйте создание объектов в onDraw.
- Кэшируйте сложные рендеры в Bitmap и рисуйте уже готовый bitmap.
- Используйте альфа-канал и blend-режимы экономно.
- Обновляйте только области, которые изменились.
- Для часто обновляемых анимаций используйте SurfaceView или RenderThread при необходимости.
Не вызывайте invalidate() в tight loop без throttling — это быстро разряжает батарею и может превысить возможности устройства.
Частые ошибки
- Инициализация Paint в onDraw → падение FPS.
- Путаница invalidate() и requestLayout() — requestLayout() пересчитывает измерения и вызывает больше работы.
- Неправильные координаты: не забывайте учитывать padding, canvas.translate() и размеры getWidth()/getHeight().
- Мерцание из‑за повторной смены LayerType или частых изменений background — используйте кэширование.
FAQ
- Нужно ли всегда использовать Path для сложных форм?
- Да, Path даёт гибкость; для статичных сложных элементов лучше отрисовать в Bitmap один раз.
- Как плавно анимировать при 60 FPS?
- Используйте postInvalidateOnAnimation() или Choreographer, обновляйте состояние с учётом дельта‑времени.
- Как отрисовать текст с выравниванием?
- Настройте paint.setTextSize(), paint.setTextAlign(Paint.Align.CENTER) и рассчитывайте baseline через paint.getFontMetrics().
Внедрите эти практики: инициализируйте ресурсы заранее, перерисовывайте только нужные области и используйте встроенные инструменты профилирования — это даст стабильную, плавную и предсказуемую графику в ваших custom View.