Özel View'da Nasıl Çizim Yapılır: Canvas, Paint ve Hata Ayıklama
Özel View'da çizim yapmak için onDraw(Canvas) metodunu geçersiz kılın, Paint nesnesini kurucu/init() metodunda önceden başlatın, Canvas.draw* (circle, line, path, text, bitmap) metodlarını kullanın ve animasyonlar için postInvalidateOnAnimation() veya kısmi yeniden çizim için invalidate(Rect) çağırın — böylece doğru, hızlı ve hata ayıklanabilir bir çizim elde edersiniz.
Canvas ve Paint Temelleri
Canvas — tuval; Paint — ayarlarla donatılmış fırça (renk, genişlik, stil, shader'lar, yumuşatma).
- View oluşturun ve kaynakları bir kez başlatın:
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);
}
}
- Sık kullanılan Canvas metodları: drawLine, drawRect, drawCircle, drawPath, drawText, drawBitmap.
- Karmaşık şekiller için Path:
Path p = new Path();
p.moveTo(50,50);
p.lineTo(150,50);
p.lineTo(100,150);
p.close();
canvas.drawPath(p, paint);
- Gradyanlar ve efektler: paint.setShader(...) üzerinden Shader (LinearGradient, RadialGradient). Şekilleri doldurmak için Paint.Style.FILL, kenarlık çizmek için STROKE kullanın.
Paint, Path ve Bitmap nesnelerini init/kurucu metodda başlatın. onDraw içinde nesne oluşturmak performansı ciddi şekilde düşürür.
Etkileşim ve Animasyon
- Dokunma işleme: onTouchEvent metodunu geçersiz kılın, koordinatları veya Path'i kaydedin ve yeniden çizim için invalidate() çağırın.
@Override public boolean onTouchEvent(MotionEvent e) {
if (e.getAction() == MotionEvent.ACTION_DOWN || e.getAction() == MotionEvent.ACTION_MOVE) {
path.lineTo(e.getX(), e.getY());
invalidate(); // veya invalidate(dirtyRect)
}
return true;
}
- Animasyon: 60 FPS için postInvalidateOnAnimation() veya Choreographer kullanın; senkronizasyon olmadan sık sık invalidate çağıran zamanlayıcılardan kaçının.
// basit bir animasyon adımı örneği
void step() {
updateState();
postInvalidateOnAnimation();
}
- Kısmi yeniden çizim için alanı belirtin: invalidate(left, top, right, bottom) veya invalidate(Rect), bu CPU/GPU tasarrufu sağlar.
- Donanımsal/yazılımsal render: Bazı efektlerle ilgili sorunlarda setLayerType(LAYER_TYPE_SOFTWARE, paint) deneyin veya tam tersini yapın — donanımsal hızlandırma genellikle daha hızlıdır.
Çizim Hata Ayıklama ve Optimizasyonu
- onDraw çağrılarını sıklığını anlamak için loglayın:
Log.d("DRAW", "onDraw at " + System.currentTimeMillis());
- Profile GPU Rendering (Geliştirici Seçeneklerinde etkinleştirilir) darboğazların nerede olduğunu gösterir.
- Android Studio'daki Layout Inspector/Hierarchy Viewer, karmaşık View hiyerarşisini ve FPS'i görmeye yardımcı olur.
- Optimizasyon ipuçları:
- onDraw içinde nesne oluşturmayı en aza indirin.
- Karmaşık render'ları Bitmap'e önbelleğe alın ve zaten hazır olan bitmap'i çizin.
- Alfa kanalı ve blend modlarını tutumlu kullanın.
- Sadece değişen alanları güncelleyin.
- Sık güncellenen animasyonlar için gerekirse SurfaceView veya RenderThread kullanın.
Throttling olmadan tight loop içinde invalidate() çağırmayın — bu pilinizi hızla tüketir ve cihazın kapasitesini aşabilir.
Sık Yapılan Hatalar
- Paint'in onDraw içinde başlatılması → FPS düşüşü.
- invalidate() ve requestLayout() karıştırılması — requestLayout() ölçümleri yeniden hesaplar ve daha fazla iş yükü yaratır.
- Yanlış koordinatlar: padding, canvas.translate() ve getWidth()/getHeight() boyutlarını dikkate almayı unutmayın.
- LayerType'nin tekrar tekrar değiştirilmesi veya arka planda sık değişiklik yapılmasından kaynaklanan titreme — önbellekleme kullanın.
SSS
- Karmaşık şekiller için her zaman Path kullanmak gerekir mi?
- Evet, Path esneklik sağlar; statik karmaşık öğeler için bunları bir kez Bitmap'e çizmek daha iyidir.
- 60 FPS'de nasıl sorunsuz animasyon yapılır?
- postInvalidateOnAnimation() veya Choreographer kullanın, durumu delta zamanı dikkate alarak güncelleyin.
- Hizalamalı metin nasıl çizilir?
- paint.setTextSize(), paint.setTextAlign(Paint.Align.CENTER) ayarlayın ve baseline'ı paint.getFontMetrics() üzerinden hesaplayın.
Bu uygulamaları hayata geçirin: Kaynakları önceden başlatın, sadece gerekli alanları yeniden çizin ve yerleşik profil oluşturma araçlarını kullanın — bu, özel View'larınızda kararlı, akıcı ve öngörülebilir grafikler sağlayacaktır.