Androidda Custom View — chizish va hodisalarni qayta ishlash

Muallif: IT Sectr Nashr etilgan: 2026-07-20 O'qish vaqti: 9 daq

Custom View — bu View sinfidan yoki uning kichik sinflaridan (Button, TextView, ImageView) meros olish va asosiy metodlarni override qilish orqali yaratilgan foydalanuvchi interfeysining maxsus komponentidir: chizish uchun onDraw, o'lchamlarni o'lchash uchun onMeasure va teginishlarni qayta ishlash uchun onTouchEvent. Google Android Developer Guide (2024) ma'lumotiga ko'ra, Custom View standart Android SDK komponentlari kerakli xatti-harakatni yoki tashqi ko'rinishni ta'minlamaganida ishlatiladi — masalan, maxsus animatsiyalar, nostandart shakllar, ixtisoslashtirilgan grafiklar va o'yin elementlari uchun.

Asosiy fikrlar

  • Custom View — onDraw, onMeasure, onTouchEvent-ni override qilish bilan View yoki uning kichik sinflaridan meros olish orqali yaratiladi.
  • Chizish Canvas API orqali amalga oshiriladi — geometrik shakllar, matn, yo'llar, Bitmap va animatsiyalar.
  • onMeasure layout parametrlari va padding-ni hisobga olgan holda View-ning to'g'ri o'lchamlari uchun javobgardir.
  • Maxsus XML atributlari res/values/attrs.xml faylida e'lon qilinadi va View konstruktorida o'qiladi.
  • onTouchEvent teginishlarni qayta ishlash imkoniyati imo-ishoralar, drag-and-drop va multitouch-ni qo'llab-quvvatlashni qo'shadi.

Androidda Custom View nima?

Custom View — bu android.view.View (yoki uning kichik sinflaridan biri) sinfidan meros oladigan va o'zining chizish, o'lchash va hodisalarni qayta ishlash mantiqini amalga oshirish uchun tizim metodlarini override qiladigan sinfdir. Custom View noyob UI komponentlarini yaratish uchun Androidning asosiy mexanizmidir.

Android Custom View yaratish uchun ikkita yondashuvni taqdim etadi: View sinfidan meros olish (onDraw orqali to'liq maxsus chizish) va mavjud View kichik sinfidan meros olish (masalan, asosiy xatti-harakatni saqlab qolgan holda funksionallik qo'shish uchun Button yoki TextView-ni override qilish).

Asosiy konstruktor Custom View Context va AttributeSet-ni qabul qilishi kerak — bu tizimga XML kodidan View yaratishga imkon beradi. Agar View faqat kodda ishlatilsa, Context bilan konstruktor yetarli. Uchinchi konstruktor uslub bilan Android mavzularini qo'llab-quvvatlash uchun kerak.

kotlin
class CustomView
    @JvmOverloads constructor(
    context: Context,
    attrs: AttributeSet? = null,
    defStyleAttr: Int = 0
) : View(context, attrs, defStyleAttr) {

    private val paint = Paint(Paint.ANTI_ALIAS_FLAG).apply {
        color = Color.BLUE
        strokeWidth = 4f
        style = Paint.Style.FILL
    }

    override fun onDraw(canvas: Canvas) {
        super.onDraw(canvas)
        canvas.drawCircle(width / 2f,
            height / 2f,
            50f, paint)
    }
}

Minimal Custom View konstruktor va onDraw-dan iborat. Biroq, Android Layout tizimida to'g'ri ishlash uchun onMeasure-ni ham override qilish kerak — aks holda View nol o'lchamlar bilan ko'rsatilishi yoki wrap_content layout parametrlariga noto'g'ri munosabat bildirishi mumkin.

Google I/O 2023 ma'lumotiga ko'ra, maxsus View-lar Google Play top 100 ilovalarining 65 foizida ishlatiladi. Custom View yaratishning eng keng tarqalgan sabablari: maxsus animatsiyalar (35%), maxsus grafiklar va diagrammalar (25%), ixtisoslashtirilgan boshqaruv elementlari (20%) va brendlashtirilgan komponentlar (20%).

onMeasure va onLayout: o'lchamlarni boshqarish

onMeasure — bu View o'zining istalgan o'lchamlarini MeasureSpec (ota-ona cheklovlari) asosida tizimga xabar qiladigan metoddir. onMeasure-ni to'g'ri amalga oshirmasdan, View wrap_content bilan nol balandlikka ega bo'lishi yoki match_parent bilan butun ekran maydonini egallashi mumkin.

MeasureSpec rejimdan (EXACTLY, AT_MOST, UNSPECIFIED) va qiymatdan iborat. EXACTLY — ota-ona aniq o'lchamni belgilagan (match_parent yoki sobit qiymat). AT_MOST — ota-ona maksimalni belgilagan (wrap_content). UNSPECIFIED — cheklovlarsiz (ScrollView, ListView).

kotlin
override fun onMeasure(
    widthMeasureSpec: Int,
    heightMeasureSpec: Int
) {
    val desiredWidth = paddingLeft + paddingRight
        + DEFAULT_WIDTH
    val desiredHeight = paddingTop + paddingBottom
        + DEFAULT_HEIGHT

    val measuredWidth = MeasureSpec.getSize(widthMeasureSpec)
    val modeWidth = MeasureSpec.getMode(widthMeasureSpec)

    val resultWidth = when (modeWidth) {
        MeasureSpec.EXACTLY -> measuredWidth
        MeasureSpec.AT_MOST ->
            desiredWidth.coerceAtMost(measuredWidth)
        else -> desiredWidth
    }

    val resultHeight = resolveSize(desiredHeight,
        heightMeasureSpec)

    setMeasuredDimension(resultWidth, resultHeight)
}

resolveSize — bu onMeasure-ni amalga oshirishni soddalashtiradigan Androidning foydali metodidir. Istalgan o'lcham va MeasureSpec-ni qabul qiladi va to'g'ri qiymatni qaytaradi: EXACTLY uchun — aniq o'lcham, AT_MOST uchun — istalgan va maksimaldan kichigi, UNSPECIFIED uchun — istalgan o'lcham.

onLayout View (ViewGroup emas) uchun odatda override qilinmaydi — ota-ona tomonidan bola elementlarini joylashtirish uchun chaqiriladi. ViewGroup uchun onLayout majburiydir — unda har bir bola View uchun layout() chaqirilishi kerak.

onDraw va Canvas API: chizish

onDraw — Custom View-ning yuragi. Bu metod Android tomonidan View har safar qayta chizilganda chaqiriladi. Unga Canvas obyekti uzatiladi, uning orqali barcha chizish amalga oshiriladi: geometrik shakllar, matn, yo'llar, Bitmap va animatsiyalar.

Canvas API barcha asosiy operatsiyalar uchun metodlarni taqdim etadi: drawCircle, drawRect, drawLine, drawPath, drawText, drawBitmap, drawArc, drawOval. Uslubni sozlash uchun Paint ishlatiladi — rang, qalinlik, to'ldirish uslubi, shrift, soyalar va effektlarni belgilaydigan obyekt.

kotlin
override fun onDraw(canvas: Canvas) {
    super.onDraw(canvas)

    // Fon
    canvas.drawRect(0f, 0f,
        width.toFloat(), height.toFloat(), bgPaint)

    // Matn
    canvas.drawText("Maxsus View",
        paddingLeft.toFloat(),
        paddingTop.toFloat() + textPaint.textSize,
        textPaint)

    // Doira
    canvas.drawCircle(
        width / 2f,
        height / 2f,
        radius, circlePaint)

    // Yo'l (Bezier egri chizig'i)
    val path = Path().apply {
        moveTo(0f, height.toFloat())
        quadTo(width / 2f, 0f,
            width.toFloat(), height.toFloat())
    }
    canvas.drawPath(path, pathPaint)
}

Paint — bu chizish uslubining konfiguratoridir. Anti-aliasing (Paint.ANTI_ALIAS_FLAG) silliq qirralar uchun majburiydir. Subpixel text (SUBPIXEL_TEXT_FLAG) matn sifatini yaxshilaydi. Style.FILL, STROKE va FILL_AND_STROKE shaklning to'ldirilishini, kontur bilan chizilishini yoki ikkalasini ham belgilaydi.

Muhim: onDraw-da Paint, Path, Rect obyektlarini yaratmang — bu chizish siklida alokatsiyalarga sabab bo'ladi va garbage collection-ni chaqiradi, bu esa FPS-ni pasaytiradi. Barcha chizish obyektlarini konstruktorda yoki init metodida yarating. Animatsiya uchun ValueAnimator yoki ObjectAnimator-dan invalidate() bilan birgalikda foydalaning.

attrs.xml da maxsus XML atributlari

Maxsus atributlar Custom View-ni standart android:layout_width yoki android:background kabi XML kodidan sozlash imkonini beradi. Atributlar res/values/attrs.xml faylida nom, tur va ixtiyoriy standart qiymat bilan e'lon qilinadi.

Atribut turlari: string, integer, float, boolean, color, dimension, enum, flag, fraction, reference (resursga havola). Har bir tur uchun Android avtomatik ravishda XML dan qiymatni tahlil qiladi va uni TypedArray-ga uzatadi.

xml
<!-- res/values/attrs.xml -->
<resources>
    <declare-styleable name="CustomView">
        <attr name="circleColor"
            format="color" />
        <attr name="circleRadius"
            format="dimension" />
        <attr name="labelText"
            format="string" />
        <attr name="showAnimation"
            format="boolean" />
    </declare-styleable>
</resources>

Custom View konstruktorida atributlar context.obtainStyledAttributes orqali o'qiladi, u TypedArray qaytaradi. TypedArray tipli kirish metodlarini taqdim etadi: getColor, getDimension, getString, getBoolean, getInt. O'qigandan so'ng, resurslarni bo'shatish uchun TypedArray-da recycle() chaqirilishi kerak.

kotlin
init {
    val typedArray = context.obtainStyledAttributes(
        attrs,
        R.styleable.CustomView
    )

    circleColor = typedArray.getColor(
        R.styleable.CustomView_circleColor,
        Color.BLUE
    )
    circleRadius = typedArray.getDimension(
        R.styleable.CustomView_circleRadius,
        50f
    )
    labelText = typedArray.getString(
        R.styleable.CustomView_labelText
    ) ?: "Default"

    typedArray.recycle()
}

XML da foydalanish: app nomlar maydonini qo'shing (xmlns:app="http://schemas.android.com/apk/res-auto") va maxsus atributlardan app:circleColor="@color/red" kabi foydalaning. attrs.xml da e'lon to'g'ri bo'lsa, Android Studio atribut turlarini avtomatik to'ldiradi va tekshiradi.

onTouchEvent bilan teginishlarni qayta ishlash

onTouchEvent — View-ning har bir teginishida chaqiriladigan metod. U hodisa turi (ACTION_DOWN, ACTION_MOVE, ACTION_UP, ACTION_CANCEL), koordinatalar, bosim va barmoqlar soni (multitouch) haqida ma'lumotga ega MotionEvent obyektini oladi.

Murakkab imo-ishoralarni (surish, masshtablash, uzoq bosish) qayta ishlash uchun onTouchEvent bilan birgalikda GestureDetector yoki ScaleGestureDetector dan foydalaning. GestureDetector onSingleTapUp, onFling, onLongPress, onDoubleTap va boshqa standart imo-ishoralarni tanib olishni soddalashtiradi.

kotlin
private val gestureDetector = GestureDetector(
    context, object : GestureDetector.SimpleOnGestureListener() {
    override fun onSingleTapUp(e: MotionEvent): Boolean {
        handleTap(e.x, e.y)
        return true
    }
})

override fun onTouchEvent(event: MotionEvent): Boolean {
    val handled = gestureDetector.onTouchEvent(event)

    when (event.action) {
        MotionEvent.ACTION_MOVE -> {
            currentX = event.x
            currentY = event.y
            invalidate()
            return true
        }
    }

    return handled || super.onTouchEvent(event)
}

Hit-testing — teginish View-ning ma'lum bir maydoniga tushganligini aniqlash. To'rtburchak maydonlar uchun Rect.contains(x, y) dan foydalaning. Doiralar uchun — markazdan masofani tekshirish: sqrt(dx^2 + dy^2) < radius. Ixtiyoriy shakllar uchun — Path.op() yoki Region.contains().

Multitouch MotionEvent.getPointerCount() va getPointerId(index) orqali qayta ishlanadi. Har bir barmoq ACTION_DOWN dan ACTION_POINTER_UP gacha saqlanadigan noyob ID oladi. ACTION_MOVE barcha faol barmoqlar bo'yicha ma'lumotlarni o'z ichiga olishi mumkin — harakatni interpolyatsiya qilish uchun getHistoricalX/Y dan foydalaning.

Custom View samaradorligini optimallashtirish

Custom View samaradorlikning tor bo'yniga aylanishi mumkin, agar onDraw tez-tez chaqirilsa (animatsiya, scroll) yoki og'ir operatsiyalarni o'z ichiga olsa. Android maxsus komponentlarning chizilishini optimallashtirish uchun bir nechta mexanizmlarni taqdim etadi.

Murakkab chizish uchun Layer type

View.setLayerType View renderini dasturiy (LAYER_TYPE_SOFTWARE) yoki apparat (LAYER_TYPE_HARDWARE) qatlamiga o'tkazish imkonini beradi. Software layer apparat tezlashishi tomonidan qo'llab-quvvatlanmaydigan murakkab Canvas grafikasi uchun foydalidir — masalan, drawTextOnPath yoki murakkab Path effektlari.

Faqat kerakli maydonni invalidate qilish

invalidate(Rect) — butun komponentni emas, faqat View-ning ko'rsatilgan maydonini qayta chizadi. Bu katta Custom View-lar (grafikalar, xaritalar, chizish canvases) uchun juda muhim, bu erda har bir kadrni to'liq qayta chizish FPS ning pasayishiga sabab bo'ladi. vsync bilan sinxronlash uchun postInvalidateOnAnimation() dan foydalaning.

kotlin
class EfficientCustomView
    @JvmOverloads constructor(
    context: Context,
    attrs: AttributeSet? = null
) : View(context, attrs) {

    // Obyektlar bir marta konstruktorda yaratiladi
    private val paint = Paint(Paint.ANTI_ALIAS_FLAG)
    private val rect = Rect()
    private val position = PointF()

    fun updatePosition(x: Float, y: Float) {
        position.set(x, y)
        // Faqat nuqta atrofidagi maydonni qayta chiz
        rect.set(
            (x - 10).toInt(),
            (y - 10).toInt(),
            (x + 10).toInt(),
            (y + 10).toInt()
        )
        invalidate(rect)
    }
}

Apparat tezlashishi Android 3.0+ (API 11+) da sukut bo'yicha yoqilgan. drawCircle, drawRect, drawBitmap Canvas operatsiyalari apparat tezlashadi va GPU da bajariladi. Biroq, drawTextOnPath, drawVertices, murakkab clipping operatsiyalari tezlashtirilmaydi — ular uchun LAYER_TYPE_SOFTWARE dan foydalaning.

Android Performance Patterns (Google, 2023) ma'lumotiga ko'ra, Custom View laglarining asosiy sabablari onDraw da alokatsiyalar (har bir kadrda obyekt yaratish), bir element o'zgarganda butun View ni qayta chizish va statik tarkib uchun LayerType.HARDWARE ning yo'qligi. Ushbu uchta muammoni tuzatish ko'p stsenariylarda FPS ni 30 dan 60 gacha oshirishni beradi.

MetodVazifaChaqirish chastotasi
onDrawView tarkibini chizishHar bir invalidate() da
onMeasureView o'lchamlarini aniqlashLayout o'zgarganda
onLayoutBola View-larni joylashtirishonMeasure dan keyin
onTouchEventTeginishlarni qayta ishlashHar bir teginishda
onSizeChangedO'lcham o'zgarishiga reaksiyaBirinchi layout va o'zgarishda

Tez-tez beriladigan savollar

Qachon Compose o'rniga Custom View dan foydalanish kerak?

Custom View (Canvas API) maksimal maxsus chizish samaradorligi (grafikalar, video muharrirlari, xaritalar), mavjud View-based kod bilan integratsiya yoki API 21 dan past Android versiyalarini qo'llab-quvvatlash zarur bo'lganda oqlanadi. Jetpack Compose ko'pgina yangi loyihalar uchun zamonaviy yondashuv bo'lib, deklarativ UI dan foydalanadi va dinamik interfeyslar uchun ko'proq mos keladi.

onMeasure ni override qilish majburiymi?

Ha, agar View XML kodida wrap_content dan foydalansa. onMeasure bo'lmasa, wrap_content match_parent kabi ishlaydi, chunki View.onMeasure ning standart amalga oshirilishi standart o'lchamni o'rnatmaydi. Agar View har doim sobit o'lchamga yoki match_parent ga ega bo'lsa, onMeasure ni o'tkazib yuborish mumkin.

Custom View ni qanday animatsiya qilish kerak?

View xususiyatlarini (rang, radius, joylashuv) o'zgartirish uchun ValueAnimator yoki ObjectAnimator dan foydalaning va qayta chizish uchun animatsiya callback ida invalidate() ni chaqiring. ValueAnimator asosiy oqimda ishlaydi va vsync bilan sinxronlanadi. Murakkab animatsiyalar (fizika, zarralar) uchun Choreographer.FrameCallback yoki Android Animation Framework dan foydalaning.

Custom View da multitouch ni qanday qayta ishlash kerak?

onTouchEvent da barmoqlar sonini aniqlash uchun MotionEvent.getPointerCount() va har bir barmoqni noyob ID bo'yicha kuzatish uchun getPointerId(i) dan foydalaning. ACTION_POINTER_DOWN / ACTION_POINTER_UP — barmoq qo'shilishi/olib tashlanishi hodisalari. Masshtablash uchun onTouchEvent bilan birga ScaleGestureDetector dan foydalaning — u pinch-to-zoom ni aniqlashni soddalashtiradi.

Jetpack Compose da Custom View dan foydalanish mumkinmi?

Ha, AndroidView orqali — View-based elementni Compose iyerarxiyasiga kiritadigan composable funksiya. AndroidView View yaratish uchun fabrika va holatni sinxronlash uchun update callback ni qabul qiladi. Bu mavjud Custom View larni to'liq qayta yozmasdan yangi Compose loyihalarida qayta ishlatish imkonini beradi.

Xulosa

  • Custom View — maxsus chizish va qayta ishlash uchun onDraw, onMeasure va onTouchEvent ni override qilish bilan View dan meros olish orqali yaratilgan maxsus Android komponenti.
  • onDraw va Canvas API — chizish asosi: Paint orqali rang, uslub va shrift sozlamalari bilan geometrik shakllar, matn, Bitmap, yo'llar.
  • onMeasure wrap_content ning to'g'ri ishlashi uchun muhim; o'lchamlarni hisoblash uchun MeasureSpec (EXACTLY, AT_MOST, UNSPECIFIED) va resolveSize dan foydalanadi.
  • Maxsus atributlar attrs.xml va TypedArray orqali Android Studio da avtomatik to'ldirish qo'llab-quvvatlashi bilan Custom View ni XML kodidan sozlash imkonini beradi.
  • onTouchEvent GestureDetector bilan teginishlar, imo-ishoralar va multitouch-ni qayta ishlashni ta'minlaydi, hit-testing esa o'zaro ta'sir maydonini aniqlaydi.
  • Samaradorlik: obyektlarni bir marta konstruktorda yarating, qisman qayta chizish uchun invalidate(Rect) va murakkab effektlar uchun LayerType dan foydalaning.
  • Custom View integratsiyalanadi Jetpack Compose bilan AndroidView orqali, bu tayyor komponentlarni yangi Compose loyihalarida qayta ishlatish imkonini beradi.

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.

Loyihani muhokama qilish

Shuningdek o'qing