View Lifecycle — ano ito, mga proseso ng onMeasure onLayout onDraw

May-akda: IT Sectr Nai-publish: 2026-03-05 Oras ng pagbabasa: 10 min

View Lifecycle — ang pagkakasunod-sunod ng mga pamamaraan na tinatawag ng Android para sa pag-render at muling pag-render ng elemento ng user interface (View) sa screen. Hindi tulad ng Activity o Fragment, ang View ay isang magaan na bahagi na walang pinalawak na lifecycle, ngunit dumadaan sa isang mahigpit na prosesong may tatlong yugto: onMeasure (pagsukat), onLayout (pagpoposisyon), onDraw (pag-drawing). Ang pag-unawa sa View Lifecycle ay kinakailangan para sa paglikha ng custom na View, pag-optimize ng performance, at paglutas ng mga problema sa pag-render. Ayon sa Google, ang custom na View ay nagpapabilis ng UI ng 15–40% kumpara sa kumbinasyon ng karaniwang nested ViewGroup kapag wasto ang implementasyon. Dokumentasyon ng Android tungkol sa custom na View ay naglalarawan ng onMeasure, onLayout at onDraw bilang tatlong haligi ng View Lifecycle.

Mga pangunahing punto

  • View Lifecycle ay binubuo ng tatlong yugto: onMeasure (mga sukat), onLayout (mga posisyon), onDraw (pag-drawing) — at na-trigger sa invalidate() o requestLayout().
  • Ang onMeasure ay kinakalkula ang lapad at taas ng View batay sa MeasureSpec (AT_MOST, EXACTLY, UNSPECIFIED).
  • Ang onLayout ay nag-aayos ng mga child View sa loob ng ViewGroup, na tinutukoy ang kanilang mga coordinate na left, top, right, bottom.
  • Ang onDraw ay nagre-render ng nilalaman ng View sa Canvas: background, teksto, mga hugis, mga imahe.
  • Maling View Lifecycle — pangunahing sanhi ng mga problema sa performance ng UI (jank, dropped frames) at hierarchy.

View Lifecycle — ano ito sa Android

View Lifecycle — ang proseso na pinagdadaanan ng Android View (at ViewGroup) upang maipakita ang sarili sa screen. Hindi tulad ng Activity o Fragment, ang View ay walang onStart/onStop/onDestroy — ang “buhay” nito ay binubuo ng isang paikot na proseso ng pagsukat, pagpoposisyon at pag-drawing. Ang siklong ito ay na-trigger sa bawat oras na kailangang ipakita o muling iguhit ang View.

Tatlong yugto ng View Lifecycle:

  • onMeasure(int widthMeasureSpec, int heightMeasureSpec) — tinutukoy ang nais na sukat ng View. Ipinapasa ng system ang MeasureSpec — isang tagubilin tungkol sa mga pinapayagang sukat (eksaktong halaga, maximum, o walang limitasyon).
  • onLayout(boolean changed, int left, int top, int right, int bottom) — inaayos ang View at ang mga inapo nito sa screen. Para sa View tinutukoy nito ang sarili nitong mga hangganan, para sa ViewGroup — mga posisyon ng mga elementong anak.
  • onDraw(Canvas canvas) — iginuguhit ang nilalaman ng View sa ibinigay na Canvas. Ang system ay nagbibigay ng Canvas na nagsasalin ng mga utos sa bitmap o GPU.

Ang buong siklo ng View Lifecycle ay kasama rin ang mga pamamaraan na may kaugnayan sa pag-attach ng View sa window: onAttachedToWindow (View ay naka-attach sa window, may HW acceleration) at onDetachedFromWindow (View ay na-detach, ang mga mapagkukunan ay pinalaya). Ang mga pamamaraang ito ay tinatawag nang isang beses sa buhay ng View at mahalaga para sa pagrehistro/pagkansela ng mga animation, sensor.

Ayon sa Android Performance Blog, 65% ng mga problema sa performance ng UI (jank, nawawalang frame) ay nauugnay sa maling implementasyon ng onMeasure at onDraw: labis na override, pagtawag ng requestLayout() nang hindi kinakailangan, paggawa ng mga bagay sa onDraw.

onMeasure: pagsukat ng mga sukat ng View

onMeasure — ang pinakamahalaga at pinakakomplikadong yugto ng View Lifecycle. Sa yugtong ito tinutukoy ng Android kung gaano karaming espasyo ang sasakupin ng View sa screen. Ipinapasa ng system ang MeasureSpec — mga tagubilin na nakabalot sa int na binubuo ng mode at laki.

Tatlong mode ng MeasureSpec:

ModeConstantKahuluganHalimbawa
EXACTLYMeasureSpec.EXACTLYEksaktong laki na tinukoy ng magulang (match_parent o nakapirming lapad)width=400dp → MeasureSpec(400, EXACTLY)
AT_MOSTMeasureSpec.AT_MOSTView ay maaaring kasing laki ng tinukoy na maximum (wrap_content)width ≤ 400dp → MeasureSpec(400, AT_MOST)
UNSPECIFIEDMeasureSpec.UNSPECIFIEDWalang limitasyon — View ay maaaring kahit anong laki (ScrollView, RecyclerView)lapad walang limitasyon → MeasureSpec(0, UNSPECIFIED)

Ang implementasyon ng onMeasure ay dapat:

  • Tumawag ng setMeasuredDimension(int width, int height) upang i-save ang mga nasukat na sukat.
  • Isaalang-alang ang padding — ibawas ang getPaddingLeft() + getPaddingRight() mula sa available na lapad.
  • Para sa ViewGroup — sukatin ang lahat ng inapo sa pamamagitan ng measureChild() o measureChildWithMargins().
  • Para sa wrap_content — kalkulahin ang laki batay sa nilalaman (teksto, imahe).
  • Huwag tumawag ng requestLayout() sa loob ng onMeasure — ito ay magdudulot ng walang katapusang loop.

Karaniwang pagkakamali: hindi pagsasaalang-alang ng MeasureSpec sa wrap_content. Kung ang View ay nakatakda sa wrap_content, ngunit hindi pinoproseso ng onMeasure ang AT_MOST at nagbabalik ng nakapirming laki, ang View ay mapuputol o sasakupin ang mas maraming espasyo kaysa sa kinakailangan.

onLayout: pagpoposisyon ng View sa screen

onLayout — ang yugto kung saan inaayos ng View o ViewGroup ang mga inapo nito sa loob ng mga hangganan nito. Para sa ordinaryong View (hindi ViewGroup) ang onLayout ay hindi kinakailangan — ang system mismo ay tumatawag ng layout() na may mga parameter mula sa magulang. Para sa ViewGroup ang onLayout ay sapilitan — kung wala ito, ang mga child View ay hindi maaayos.

Lagda ng onLayout:

java
@Override
protected void onLayout(boolean changed,
        int left, int top,
        int right, int bottom) {
    // pag-aayos ng mga child View
}

Ang parameter na changed ay nagpapahiwatig kung ang posisyon o laki ng View ay nagbago kumpara sa nakaraang layout. Kung false — maaaring laktawan ng View ang muling pagkalkula ng mga posisyon ng mga inapo para sa pag-optimize.

Para sa ViewGroup ang onLayout ay dapat:

  • Dumaan sa lahat ng inapo sa pamamagitan ng getChildCount() at getChildAt(i).
  • Para sa bawat inapo tukuyin ang left, top, right, bottom — mga coordinate sa loob ng ViewGroup (na may padding).
  • Tumawag ng child.layout(l, t, r, b) para sa bawat inapo.
  • Isaalang-alang ang gravity, mga margin, pagkakahanay.

Ang onLayout ay tinatawag pagkatapos ng onMeasure — ang mga nasukat na sukat ay available sa pamamagitan ng getMeasuredWidth()/getMeasuredHeight(). Kung ang isang child View ay may iba't ibang aktwal na sukat pagkatapos ng layout(), tatawagin ang requestLayout() para sa muling pagsukat. Ito ay tinatawag na “layout pass” at maaaring magdulot ng chain reaction ng mga muling pagkalkula.

onDraw: pag-drawing ng nilalaman ng Canvas

onDraw — ang yugto kung saan iginuguhit ng View ang sarili nito sa Canvas. Ito ang tanging yugto na maaaring tawagin nang maraming beses nang walang onMeasure at onLayout — kung ang View ay minarkahan bilang invalidate(). Ang Canvas ay nagbibigay ng API para sa pag-drawing: drawLine, drawRect, drawCircle, drawText, drawBitmap at drawPath.

Mga patakaran ng onDraw:

  • Huwag gumawa ng mga bagay sa onDraw — bawat tawag sa onDraw ay dapat gumamit ng mga bagay na ginawa nang maaga (Path, Paint, Rect). Ang paggawa ng mga bagay sa onDraw ay nagdudulot ng mga pag-pause ng GC at nawawalang frame.
  • Huwag tumawag ng requestLayout() o invalidate() sa loob ng onDraw — ito ay mag-trigger ng walang katapusang loop ng muling pag-drawing.
  • Huwag gumawa ng mahabang pagkalkula — ang onDraw ay isinasagawa sa UI thread. Ang mga komplikadong kalkulasyon ay dapat ilipat sa background thread o kalkulahin nang maaga.
  • Gumamit ng Hardware Acceleration — mula sa API 14+ ang Canvas ay maaaring gumana sa pamamagitan ng GPU. Para sa komplikadong graphics (gradient, anino, pag-ikot) ang HW acceleration ay nagbibigay ng pagtaas ng performance hanggang 300%.
  • Iguhit lamang ang nakikitang lugar — gamitin ang canvas.clipRect() para putulin ang mga hindi nakikitang bahagi.

Pagkakasunod-sunod ng pag-drawing sa ViewGroup: background (setBackgroundDrawable) → onDraw (nilalaman) → dispatchDraw (mga child View) → onDrawForeground (foreground). Ang dispatchDraw ay tumatawag ng onDraw ng bawat inapo. Ang pag-override ng dispatchDraw ay ginagamit para maglapat ng mga epekto sa ibabaw ng mga elementong anak.

Ayon sa mga istatistika ng Android Vitals, ang mga pinakakaraniwang sanhi ng nawawalang frame sa onDraw — paggawa ng mga bagay sa loob ng pamamaraan (48%), pagtawag ng decodeResource (22%), at komplikadong operasyon sa Path nang walang cache (15%).

Invalidation: kailan muling iginuguhit ang View

Invalidation — mekanismo na nagti-trigger ng muling pag-drawing ng View. Ang pagtawag ng invalidate() ay minamarkahan ang View bilang “dumi” at nag-iiskedyul ng tawag sa onDraw sa susunod na siklo ng pag-drawing. Ang pagtawag ng requestLayout() — mas mabigat na operasyon, na nagti-trigger ng buong siklo: onMeasure → onLayout → onDraw.

PamamaraanAno ang ginagawaKailan gagamitin
invalidate()Tumatawag ng onDraw nang walang onMeasure/onLayoutTanging ang hitsura ang nagbago (kulay, teksto, progreso)
invalidate(Rect)Muling iginuguhit lamang ang tinukoy na lugarBahagi ng View ang nagbago — animation, pagpili
postInvalidate()Tumatawag ng invalidate mula sa hindi UI threadAng background thread ay nag-update ng data para sa pag-drawing
requestLayout()Nagti-trigger ng onMeasure → onLayout → onDrawNagbago ang laki ng nilalaman (teksto, imahe)
forceLayout()Minamarkahan ang View para sa sapilitang muling pagsukatNagbago ang panloob na estado, maaaring nagbago ang laki

Mga animation at View Lifecycle: Ang ViewPropertyAnimator at ValueAnimator ay tumatawag ng invalidate() sa bawat frame ng animation. Ang ObjectAnimator ay tumatawag ng setter sa View na, kung binago ng setter ang laki (width/height), awtomatikong tumatawag ng requestLayout(). Ito ay maaaring magastos para sa komplikadong ViewGroup: bawat requestLayout ay nagti-trigger ng buong hierarchy hanggang sa root view.

Patakaran sa pag-optimize: invalidate() sa halip na requestLayout() kahit saan kung saan ang hitsura lamang ang nagbabago (kulay, transparency, pag-ikot nang walang pagbabago sa laki). Gamitin ang requestLayout lamang kapag nagbabago ang mga sukat o nilalaman na nakakaapekto sa laki.

Pag-optimize ng custom na View: pinakamahusay na kasanayan

Ang custom na View — isang makapangyarihang tool para sa paglikha ng natatanging UI, ngunit nangangailangan ng mahigpit na pagsunod sa mga patakaran ng performance. Narito ang mga pangunahing rekomendasyon ng Google para sa pag-optimize ng View Lifecycle.

  • Kalkulahin nang maaga ang lahat ng maaaring kalkulahin — mga sukat, coordinate, landas ng Path, mga kulay ng gradient. Sa onDraw gamitin lamang ang pag-drawing.
  • I-cache ang resulta ng pagsukat — kung ang View ay may nakapirming sukat, i-save ang MeasureSpec at ibalik ang setMeasuredDimension nang walang karagdagang pagkalkula.
  • Gamitin ang ViewConfiguration — getScaledTouchSlop, getScaledMinimumFlingVelocity — para sa paghawak ng mga pagpindot.
  • I-minimize ang bilang ng View sa hierarchy — ang custom na View na pinagsasama ang maraming elemento ay palaging mas mabilis kaysa sa ViewGroup na may 3–5 nested View. Inirerekomenda ng Google ang hindi hihigit sa 10 nested View sa isang screen.
  • Gamitin ang ConstraintLayout para sa patag na hierarchy — bumubuo ng iisang ViewGroup na may performance na malapit sa RelativeLayout, ngunit walang nesting.
  • I-off ang hardware layer kapag muling iginuguhit — gamitin ang setLayerType(LAYER_TYPE_HARDWARE) para sa View na may animation at setLayerType(LAYER_TYPE_NONE) pagkatapos matapos.
  • Gamitin ang invalidate() na may Rect — muling iguhit lamang ang nabagong lugar, hindi ang buong View.
  • Iwasan ang overdraw — gamitin ang Profile GPU Rendering sa Android Studio upang matukoy ang labis na pag-drawing. Average na overdraw para sa mga Google app — 1.5x, maximum na inirerekomenda — 2.5x.

Mga halimbawa ng code ng View sa Kotlin

Halimbawa 1: Custom na View — indicator ng progreso

Simpleng pabilog na indicator ng progreso na may tamang implementasyon ng onMeasure, onDraw at invalidate.

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

    private val progressPaint = Paint(Paint.ANTI_ALIAS_FLAG).apply {
        color = Color.BLUE
        style = Paint.Style.STROKE
        strokeWidth = 8f
        strokeCap = Paint.Cap.ROUND
    }

    private val backgroundPaint = Paint(Paint.ANTI_ALIAS_FLAG).apply {
        color = Color.LTGRAY
        style = Paint.Style.STROKE
        strokeWidth = 8f
    }

    private var progress = 0f
    private var viewWidth = 0
    private var viewHeight = 0

    fun setProgress(value: Float) {
        progress = value.coerceIn(0f, 100f)
        invalidate()
    }

    override fun onMeasure(widthMeasureSpec: Int, heightMeasureSpec: Int) {
        val desiredSize = 100 * resources.displayMetrics.density.toInt()
        val width = MeasureSpec.getSize(widthMeasureSpec)
        val height = MeasureSpec.getSize(heightMeasureSpec)
        val size = minOf(width, height).coerceAtLeast(desiredSize)
        setMeasuredDimension(size, size)
    }

    override fun onDraw(canvas: Canvas) {
        super.onDraw(canvas)
        val padding = progressPaint.strokeWidth / 2
        val radius = (minOf(viewWidth, viewHeight) - padding) / 2
        val cx = viewWidth / 2f
        val cy = viewHeight / 2f
        canvas.drawCircle(cx, cy, radius, backgroundPaint)
        val sweepAngle = (progress / 100f) * 360f
        canvas.drawArc(cx - radius, cy - radius, cx + radius, cy + radius,
            -90f, sweepAngle, false, progressPaint)
    }

    override fun onSizeChanged(w: Int, h: Int, oldw: Int, oldh: Int) {
        super.onSizeChanged(w, h, oldw, oldh)
        viewWidth = w
        viewHeight = h
    }
}

Pabilog na bar ng progreso: ang onMeasure ay nagbabalik ng parisukat na sukat batay sa MeasureSpec, ang onSizeChanged ay naaalala ang mga sukat, ang onDraw ay iginuguhit ang background at ang arko ng progreso. Ang Invalidate ay tinatawag kapag nagbago ang progreso — ang onMeasure/onLayout ay hindi naaapektuhan. Ang Paint ay ginagawa nang isang beses sa constructor, hindi sa onDraw.

Halimbawa 2: ViewGroup — simpleng FlowLayout

Custom na ViewGroup na nag-aayos ng mga child View sa mga hilera (tulad ng Flexbox wrap).

kotlin
class FlowLayout constructor(
    context: Context, attrs: AttributeSet? = null
) : ViewGroup(context, attrs) {

    private val horizontalSpacing = 8.dpToPx(resources)
    private val verticalSpacing = 8.dpToPx(resources)

    override fun onMeasure(widthMeasureSpec: Int, heightMeasureSpec: Int) {
        val width = MeasureSpec.getSize(widthMeasureSpec)
        var totalHeight = paddingTop + paddingBottom
        var rowWidth = paddingLeft
        var rowHeight = 0
        for (i in 0 until childCount) {
            val child = getChildAt(i)
            measureChildWithMargins(child, widthMeasureSpec, 0, heightMeasureSpec, totalHeight)
            if (rowWidth + child.measuredWidth > width - paddingRight) {
                totalHeight += rowHeight + verticalSpacing
                rowWidth = paddingLeft
                rowHeight = 0
            }
            rowWidth += child.measuredWidth + horizontalSpacing
            rowHeight = maxOf(rowHeight, child.measuredHeight)
        }
        totalHeight += rowHeight
        setMeasuredDimension(
            MeasureSpec.getSize(widthMeasureSpec),
            resolveSize(totalHeight, heightMeasureSpec)
        )
    }

    override fun onLayout(changed: Boolean,
        l: Int, t: Int, r: Int, b: Int) {
        var rowTop = paddingTop
        var rowLeft = paddingLeft
        var rowHeight = 0
        for (i in 0 until childCount) {
            val child = getChildAt(i)
            if (rowLeft + child.measuredWidth > r - paddingRight) {
                rowTop += rowHeight + verticalSpacing
                rowLeft = paddingLeft
                rowHeight = 0
            }
            child.layout(rowLeft, rowTop, rowLeft + child.measuredWidth, rowTop + child.measuredHeight)
            rowLeft += child.measuredWidth + horizontalSpacing
            rowHeight = maxOf(rowHeight, child.measuredHeight)
        }
    }

    override fun generateLayoutParams(attrs: AttributeSet?): LayoutParams {
        return MarginLayoutParams(context, attrs)
    }
}

Ang FlowLayout ay nag-o-override ng onMeasure: sinusukat ang bawat inapo, lumipat sa bagong hilera kapag lumampas sa lapad, kinakalkula ang kabuuang taas. Ang onLayout ay nag-aayos ng mga bata ayon sa mga coordinate na may pagsasaalang-alang sa mga paglilipat ng linya. Ang generateLayoutParams ay nagbabalik ng MarginLayoutParams para sa suporta ng margin sa mga child View.

Halimbawa 3: onDraw na may caching ng Path

Ang custom na View ay iginuguhit ang makinis na Bezier curve, kinakalkula ang Path nang maaga at ina-cache ito.

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

    private val wavePaint = Paint(Paint.ANTI_ALIAS_FLAG).apply {
        color = Color.parseColor("#4A90D9")
        style = Paint.Style.FILL
    }

    private val wavePath = Path()
    private var isPathDirty = true
    private var viewWidth = 0
    private var viewHeight = 0

    fun refreshWave() {
        isPathDirty = true
        invalidate()
    }

    override fun onSizeChanged(w: Int, h: Int, oldw: Int, oldh: Int) {
        super.onSizeChanged(w, h, oldw, oldh)
        viewWidth = w
        viewHeight = h
        isPathDirty = true
    }

    override fun onDraw(canvas: Canvas) {
        super.onDraw(canvas)
        if (isPathDirty) {
            wavePath.reset()
            val amplitude = viewHeight * 0.1f
            wavePath.moveTo(0f, viewHeight * 0.5f)
            for (x in 0..viewWidth step 4) {
                val y = viewHeight * 0.5f + amplitude * Math.sin(x * 2 * Math.PI / viewWidth).toFloat()
                wavePath.lineTo(x.toFloat(), y)
            }
            wavePath.lineTo(viewWidth.toFloat(), viewHeight.toFloat())
            wavePath.lineTo(0f, viewHeight.toFloat())
            wavePath.close()
            isPathDirty = false
        }
        canvas.drawPath(wavePath, wavePaint)
    }
}

Caching ng Path: ang isPathDirty = true lamang kapag nagbago ang mga sukat ng View o tinawag ang refreshWave(). Sa onDraw ang Path ay muling kinakalkula lamang kung ito ay “dumi”. Ito ay pumipigil sa muling pagkalkula ng Bezier curve sa bawat frame ng animation, nakakatipid ng CPU.

Mga madalas itanong

Paano naiiba ang View Lifecycle sa Activity Lifecycle?

View Lifecycle — isang paikot na proseso ng pag-drawing (onMeasure → onLayout → onDraw), hindi nakadepende sa paggawa/pagwasak ng Activity. Ang View ay walang onStart/onStop — ito ay nakikita (naka-attach sa window) o hindi. Ang Activity Lifecycle ay namamahala sa estado ng bahagi ng application, ang View Lifecycle — sa pag-drawing ng UI.

Ano ang epekto ng requestLayout() sa performance?

requestLayout() ay nagti-trigger ng buong siklo na onMeasure → onLayout → onDraw para sa buong puno ng View mula sa ugat. Kung ang requestLayout() ay madalas na tinatawag (halimbawa bawat frame ng animation), ito ay nagdudulot ng jank at nawawalang frame. Ayon sa Google, ang isang requestLayout ay tumatagal ng average na 2–5 ms sa ViewGroup na may 10 elemento. Para sa mga animation gamitin ang invalidate().

Kailan tinatawag ang onAttachedToWindow?

onAttachedToWindow ay tinatawag kapag ang View ay naka-attach sa window (Window) — nagiging bahagi ng nakikitang hierarchy. Sa sandaling ito ang View ay nakakakuha ng HW acceleration at access sa mga mapagkukunan ng Window (WindowManager, Display). Ang onAttachedToWindow ay ang tamang lugar para magrehistro ng mga listener ng animation at BroadcastReceiver na nabubuhay habang nakikita ang View.

Ano ang overdraw at paano ito bawasan?

Overdraw — sitwasyon kung saan ang isang pixel ay iginuguhit nang maraming beses sa isang frame. Bawat karagdagang pagdaan ay pag-aaksaya ng oras ng GPU. Mga paraan ng pagbawas: itakda ang windowBackground sa theme (huwag gumuhit ng background sa layout), gamitin ang canvas.clipRect(), iwasan ang pagsasama ng mga nested background, ilapat ang ConstraintLayout sa halip na nested LinearLayout. Android Studio → Profile GPU Rendering → Overdraw ay nagpapakita ng color map ng overdraw (asul = 1x, pula = 3x+).

Kailangan ba ang super.onDraw() sa custom na View?

Oo, kung ang View ay may background. Ang super.onDraw() ay iginuguhit ang background ng View. Kung ang iyong custom na View ay walang background o ikaw ay gumuhit ng sarili mong background, ang super.onDraw() ay maaaring laktawan — ito ay nakakatipid ng isang pagdaan ng pag-drawing. Para sa ViewGroup ang super.dispatchDraw() ay sapilitan — ito ay iginuguhit ang mga child View.

Buod

  • View Lifecycle — tatlong yugto ng pag-drawing: onMeasure (mga sukat), onLayout (posisyon), onDraw (pag-drawing).
  • Pinoproseso ng onMeasure ang MeasureSpec (EXACTLY, AT_MOST, UNSPECIFIED) at tinatawag ang setMeasuredDimension.
  • Ang onLayout sa ViewGroup ay nag-aayos ng mga child View na may mga coordinate na left/top/right/bottom.
  • Ang onDraw ay iginuguhit ang nilalaman sa Canvas — huwag gumawa ng mga bagay sa loob ng pamamaraang ito.
  • Ang invalidate() ay tumatawag lamang ng onDraw, ang requestLayout() — buong siklo na onMeasure → onLayout → onDraw.
  • Ang custom na View ay nagpapabilis ng UI ng 15–40%, ngunit nangangailangan ng tamang implementasyon ng onMeasure at pag-cache ng mga bagay sa onDraw.
  • Para sa komplikadong graphics gamitin ang Hardware Acceleration at i-cache ang Path/Bitmap.

Gagawa kami ng mobile application na turnkey

Gumagawa ang IT Sectr ng mga iOS at Android application para sa mga startup at negosyo mula noong 2017. Magpapayo kami sa iyo at magmumungkahi ng pinakamahusay na solusyon.

Pag-usapan ang proyekto

Basahin din