onDraw() — Android SDK-dagi View sinfining asosiy metodi bo'lib, ko'rinish mazmunini chizish uchun javobgardir. Sistem onDraw-ni View tashqi ko'rinishi har yangilanganda chaqiradi — boshlang'ich render paytida, invalidate() dan so'ng yoki o'lchamlar o'zgarganda. Android Developers Documentation (2026) ga ko'ra, Canvas API yordamida onDraw-ni override qilish Android ilovalarida maxsus grafika yaratishning asosiy usulidir.
Asosiy ma'lumotlar
onDraw(Canvas canvas) — bu android.view.View sinfining himoyalangan metodi bo'lib, View render qilinishi kerak bo'lganda Android sistemasi tomonidan chaqiriladi. Dasturchi bu metodni maxsus chizishni amalga oshirish uchun override qiladi: shakllar, matn, rasmlar, gradientlar, animatsiya. Canvas parametri barcha chizish operatsiyalari bajariladigan grafik sirt hisoblanadi.
Metod imzosi oddiy: override fun onDraw(canvas: Canvas). Ushbu metod ichida yangi obyektlar yaratish (GC yukini oldini olish uchun), uzoq operatsiyalarni bajarish yoki tarmoq bilan ishlash mumkin emas. View shuningdek o'z hayot siklida onLayout (pozitsiyalarni hisoblash) va dispatchDraw (bolalar elementlarini chizish) o'rtasida onDraw metodini o'z ichiga oladi.
View dan meros olishda har qanday mazmunni ko'rsatish uchun onDraw-ni override qilish majburiydir — aks holda View bo'sh bo'ladi. Mavjud kichik sinflardan (TextView, ImageView, Button) meros olishda onDraw-ni override qilish ixtiyoriydir va standart mazmun ustiga qo'shimcha grafika qo'shish uchun ishlatiladi.
Android View chizishni qat'iy belgilangan tartibda bajaradi, bu tartib asosiy oqimdan (UI thread) chaqiriladi. To'liq sikl uch fazadan iborat: measure (o'lchamlarni o'lchash), layout (pozitsiyalarni hisoblash) va draw (chizish). onDraw draw fazasining bir qismidir va View o'lchamlari va joylashuvi aniqlangandan so'ng chaqiriladi.
draw(Canvas canvas) — bu onDraw va dispatchDraw-ni chaqiradigan View-ning public metodidir. draw metodi override qilish uchun mo'ljallanmagan — uning o'rniga onDraw override qilinadi. Joriy View uchun onDraw bajarilgandan so'ng, dispatchDraw chaqiriladi, u barcha bolalar View-lari uchun draw-ni rekursiv chaqiradi (agar joriy View ViewGroup konteyneri bo'lsa).
onDraw quyidagi shartlarda chaqiriladi: 1) View birinchi marta ko'rinadigan bo'ladi (setVisibility(VISIBLE) dan so'ng); 2) ilova ushbu View yoki uning ota-onasi uchun invalidate() chaqiradi; 3) View o'lchami o'zgaradi (yangi layout); 4) View bilan bog'liq animatsiya o'zgaradi (ValueAnimator yoki ObjectAnimator orqali); 5) View holati o'zgaradi (pressed, focused, enabled).
Android 3.0 (API 11) dan boshlab, ko'pchilik Canvas operatsiyalari GPU orqali apparat tezlashtirish bilan bajariladi. Dasturchi tezlashtirish yoqilganligini canvas.isHardwareAccelerated() orqali tekshirishi mumkin. Apparat tezlashtirishda ba'zi Canvas operatsiyalari qo'llab-quvvatlanmaydi (masalan, to'g'ri to'rtburchak bo'lmagan maydon bilan clipPath) va e'tiborga olinmasligi yoki xatolarga sabab bo'lishi mumkin.
Canvas chizish uchun boy metodlar to'plamini taqdim etadi. Barcha metodlar joriy koordinatalar tizimida ishlaydi, bu tizim transformatsiyalar (translate, rotate, scale, skew) orqali o'zgartirilishi mumkin. Har bir metod rang, uslub, chiziq qalinligi, effektlar va tekislashni belgilaydigan Paint obyektini qabul qiladi.
| Canvas metodi | Maqsad | Paint ning asosiy parametrlari |
|---|---|---|
| drawCircle | Doira chizish | centerX, centerY, radius, paint |
| drawRect | To'rtburchak chizish | left, top, right, bottom, paint |
| drawLine | Chiziq chizish | startX, startY, endX, endY, paint |
| drawPath | Ixtiyoriy kontur chizish | path, paint |
| drawBitmap | Rasm chizish | bitmap, srcRect, dstRect, paint |
| drawText | Matn chizish | text, x, y, paint |
| drawArc | Yoy yoki sektor chizish | ovalRect, startAngle, sweepAngle, useCenter, paint |
| drawOval | Oval chizish | ovalRect, paint |
Paint chizish uslubini belgilaydi: rang (setColor), chiziq qalinligi (setStrokeWidth), to'ldirish uslubi (setStyle — FILL, STROKE, FILL_AND_STROKE), tekislash (setAntiAlias), effektlar (setShadowLayer, setMaskFilter) va gradientlar (setShader). Paint-ni View konstruktorida bir marta yaratish va sozlash tavsiya etiladi, onDraw ichida emas — bu chizish siklida obyekt yaratilishining oldini oladi.
Canvas koordinatalar tizimidan foydalanadi, unda X o'qi o'ngga, Y o'qi esa pastga yo'naltirilgan. Koordinatalar boshi (0, 0) View-ning yuqori chap burchagidir. draw metodlarini chaqirishdan oldin dasturchi koordinatalar tizimini canvas.translate(dx, dy), canvas.rotate(degrees, px, py), canvas.scale(sx, sy, px, py) orqali o'zgartirishi mumkin. Barcha keyingi chizish operatsiyalari transformatsiya qilingan tizimda bajariladi.
onDraw asosiy UI oqimida bajariladi va uning davomiyligi to'g'ridan-to'g'ri sekundiga kadrlar soniga (fps) ta'sir qiladi. 60 fps ni saqlash uchun onDraw metodi 16 millisekunddan ko'p bo'lmagan vaqtda tugashi kerak. Har qanday sekinlashuv kadrlarning o'tkazib yuborilishiga (jank) olib keladi, bu vizual ravishda animatsiyaning qotib qolishi yoki aylantirishda kechikish sifatida qabul qilinadi.
Asosiy qoidalar onDraw optimallashtirishiga quyidagilar kiradi: 1) onDraw ichida obyekt yaratmang — barcha Paint, Path, Rect sinf maydonlari bo'lishi kerak; 2) xotira ajratmang (new) — bu axlat yig'uvchini (GC) ishga tushiradi va kadrlarning o'tkazib yuborilishiga sabab bo'ladi; 3) murakkab operatsiyalarni Bitmap.createBitmap orqali Bitmapda keshlang va tayyor Bitmapni chizing; 4) kirish-chiqish operatsiyalari yoki resurslarni yuklashni bajarmang.
clipRect chizish maydonini belgilangan to'rtburchak bilan cheklaydi. Canvas ko'rinadigan maydondan tashqaridagi piksellarni renderlashga vaqt sarflamasligi uchun ishlatiladi. Katta ro'yxatlarni aylantirish yoki masshtablashda ayniqsa samarali: clipRect-ni ko'rinadigan maydonga (dirty rect) o'rnating va Canvas faqat ko'rinadigan narsalarni chizadi.
canvas.save() Canvas-ning joriy holatini (transformatsiya va clip) stekda saqlaydi. canvas.restore() oxirgi saqlangan holatni tiklaydi. Bu vaqtinchalik transformatsiyalar uchun zarur: holatni saqlaysiz, translate/rotate qo'llaysiz, chizasiz, keyin tiklaysiz. save va restore yengil va oqilona foydalanishda (10–15 darajadan kam ichki joylashuv) unumdorlikka ta'sir qilmaydi.
invalidate() — bu View metodi bo'lib, sistemaga View mazmuni eskirganligi va uni qayta chizish kerakligi haqida xabar beradi. invalidate chaqiruvi onDraw chaqiriladigan yangi draw siklini boshlaydi. invalidate faqat UI oqimidan (main thread) chaqirilishi kerak. Fon oqimidan chaqirish uchun postInvalidate ishlatiladi.
postInvalidate() — invalidate-ning oqim-xavfsiz versiyasi bo'lib, qayta chizish so'rovini Handler orqali asosiy oqim navbatiga yuboradi. Ma'lumotlarni yuklash yoki hisoblash tugagandan so'ng View-ni yangilash kerak bo'lganda fon vazifalarida ishlatiladi. UI bilan sinxronizatsiya uchun runOnUiThread bilan birlashtiriladi.
Qisman qayta chizish uchun invalidate(Rect dirty) yoki invalidate(int l, int t, int r, int b) ishlatiladi. Bu sistemaga faqat belgilangan maydon o'zgarganligini, butun View emasligini ko'rsatadi. Android faqat dirty rect-ni qayta chizib renderlashni optimallashtiradi, bu qisman yangilanishlar bilan animatsiyalarda unumdorlikni sezilarli darajada oshiradi.
Keling, Kotlin yordamida Android uchun maxsus View-lar yaratishda onDraw-ni override qilishning amaliy misollarini ko'rib chiqaylik.
Misol animatsion to'ldirish bilan dumaloq progress ko'rsatkichi yaratadi. onDraw ikkita doira chizadi: kulrang fon va rangli to'ldiriladigan, yoyi joriy progress bilan belgilanadi. setProgress da invalidate chaqiruvi qiymat o'zgarganda qayta chizishni ta'minlaydi.
class CircularProgressView
@JvmOverloads constructor(
context: Context,
attrs: AttributeSet? = null
) : View(context, attrs) {
private val bgPaint = Paint().apply {
style = Paint.Style.STROKE
strokeWidth = 12f
color = Color.parseColor("#E0E0E0")
isAntiAlias = true
}
private val progressPaint = Paint().apply {
style = Paint.Style.STROKE
strokeWidth = 12f
color = Color.BLUE
isAntiAlias = true
strokeCap = Paint.Cap.ROUND
}
var progress: Float = 0f
set(value) {
field = value.coerceIn(0f, 1f)
invalidate()
}
override fun onDraw(canvas: Canvas) {
super.onDraw(canvas)
val size = minOf(width, height) - 24f
val oval = RectF(12f, 12f,
12f + size, 12f + size)
canvas.drawArc(oval, 270f, 360f, false, bgPaint)
canvas.drawArc(oval, 270f,
progress * 360f,
false, progressPaint)
}
}
Misol ustida matn bo'lgan gradient to'rtburchak chizadi. Gradient LinearGradient (Shader) orqali, matn esa drawText orqali yaratiladi. Ikkala Paint konstruktorda bir marta yaratiladi, onDraw da esa faqat to'rtburchak o'lchami joriy View kengligiga qarab o'zgartiriladi.
class GradientTextView(context: Context)
: View(context) {
private val shaderPaint = Paint().apply {
isAntiAlias = true
}
private val textPaint = Paint().apply {
color = Color.WHITE
textSize = 48f
isAntiAlias = true
textAlign = Paint.Align.CENTER
}
override fun onDraw(canvas: Canvas) {
super.onDraw(canvas)
val gradient = LinearGradient(
0f, 0f, width.toFloat(), 0f,
Color.parseColor("#FF6B35"),
Color.parseColor("#FF0040"),
Shader.TileMode.CLAMP
)
shaderPaint.shader = gradient
canvas.drawRect(0f, 0f,
width.toFloat(),
height.toFloat(), shaderPaint)
val xCenter = width / 2f
val yCenter = height / 2f
val yOffset = (textPaint.descent() +
textPaint.ascent()) / 2f
canvas.drawText("Canvas dan salom",
xCenter, yCenter - yOffset,
textPaint)
}
}
Misol har 1000 millisekundda chizishni yangilaydigan animatsion soat yaratadi. onDraw dagi postDelayed bir soniyadan so'ng invalidate chaqirib, cheksiz qayta chizish siklini yaratadi. Soat millari drawLine orqali turli uzunlik va qalinlikda chiziladi.
class AnalogClockView(context: Context)
: View(context) {
private val handPaint = Paint().apply {
style = Paint.Style.STROKE
isAntiAlias = true
}
override fun onDraw(canvas: Canvas) {
super.onDraw(canvas)
val cx = width / 2f
val cy = height / 2f
val radius = minOf(cx, cy) - 20f
val now = Calendar.getInstance()
val hours = now.get(Calendar.HOUR) % 12
val minutes = now.get(Calendar.MINUTE)
val seconds = now.get(Calendar.SECOND)
val secondAngle = Math.toRadians(
seconds * 6f - 90f)
handPaint.strokeWidth = 2f
handPaint.color = Color.RED
canvas.drawLine(cx, cy,
cx + cos(secondAngle) * radius * 0.8f,
cy + sin(secondAngle) * radius * 0.8f,
handPaint)
postDelayed({ invalidate() }, 1000)
}
}
Tez-tez so'raladigan savollar
Yo'q, onDraw-ni to'g'ridan-to'g'ri chaqirish mumkin emas. Qayta chizish so'rovi uchun invalidate() (UI oqimidan) yoki postInvalidate() (fon oqimidan) foydalaning. Sistem o'zi onDraw qachon chaqirilishini hal qiladi va bir nechta invalidate-larni bitta o'tishda birlashtirib renderlashni optimallashtiradi.
Sabablar: View yashirin (setVisibility(GONE) yoki INVISIBLE); View Window ierarxiyasiga qo'shilmagan; View o'lchami 0 (width yoki height = 0); setWillNotDraw(true) chaqiriladi (ViewGroup uchun sukut bo'yicha true). Nosozliklarni tuzatishda ushbu bandlarning har birini tekshiring.
60 fps da onDraw sekundiga 60 martagacha chaqirilishi mumkin. 120 fps da (120 Hz displeyli qurilmalarda) — 120 martagacha. Har bir chaqiruv ~8–16 millisekundga tugashi kerak. ObjectAnimator yoki ValueAnimator orqali faol animatsiyalarda chastota animatsiya kadrlari soni bilan belgilanadi.
onDraw View-ning o'z mazmunini chizish uchun javobgardir. dispatchDraw bolalar View-larini chizish uchun javobgardir (ViewGroup da). dispatchDraw onDraw dan so'ng chaqiriladi va barcha bolalar elementlarini rekursiv ravishda aylanadi. Oddiy View (ViewGroup emas) uchun dispatchDraw bo'sh.
Ha, Canvas Canvas(bitmap) orqali Bitmap uchun yaratilishi mumkin va istalgan oqimda chizish mumkin. Bu murakkab grafikani fonda oldindan hisoblash uchun ishlatiladi. Biroq, onDraw da uzatiladigan Canvas sistemaga tegishli va faqat UI oqimida onDraw metodi ichida ishlatilishi mumkin.
Xulosa
Biz kalit topshirig'i bilan mobil ilovani ishlab chiqamiz
IT Sectr 2017-yildan beri startaplar va korxonalar uchun iOS va Android ilovalarini yaratadi. Biz sizga maslahat beramiz va eng yaxshi yechimni taklif qilamiz.