0Pricing
Android Academy · Lezione

View personalizzate

Disegni componenti dell'interfaccia personalizzati da zero. Estenda View, implementi onMeasure e onDraw con Canvas e Paint, definisca attributi XML personalizzati e costruisca view composite.

View personalizzate è una lezione Android Academy gratuita su CoddyKit. Questa è la lezione 3 di 5. Puoi leggere la lezione completa qui gratuitamente — poi esercitati direttamente nel browser con un editor di codice integrato e un tutor IA disponibile 24/7. Fa parte del percorso di apprendimento Android Academy, e i tuoi progressi si sincronizzano tra il web e l'app CoddyKit. Il corso Android Academy include 5 lezioni in totale.

Perché utilizzare view personalizzate?

A volte le view Android integrate non fanno esattamente ciò che serve. Le view personalizzate consentono di:

  • D disegnare forme, grafici, anelli di avanzamento o diagrammi che non esistono nell'SDK
  • Creare componenti UI con il brand, utilizzati in modo coerente in tutta l'app
  • Combinare più view in un unico componente riutilizzabile (Compound View)
  • Ottenere prestazioni migliori eliminando gerarchie di layout annidate

Estensione di View

Crei una view personalizzata estendendo View o una sottoclasse come ImageView. Esegua l'override del costruttore richiesto:

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

    var progress: Float = 0f
        set(value) {
            field = value.coerceIn(0f, 100f)
            invalidate()   // trigger redraw
        }

    // onMeasure and onDraw go here
}

onMeasure()

onMeasure() comunica al genitore quanto vorrebbe essere grande questa view. Chiami sempre setMeasuredDimension() alla fine:

override fun onMeasure(widthMeasureSpec: Int, heightMeasureSpec: Int) {
    val desiredSize = 200  // dp → pixels
    val px = (desiredSize * resources.displayMetrics.density).toInt()

    val width  = resolveSize(px, widthMeasureSpec)
    val height = resolveSize(px, heightMeasureSpec)

    // Square: same width and height
    val size = minOf(width, height)
    setMeasuredDimension(size, size)
}

Paint — lo strumento di disegno

Un oggetto Paint contiene le informazioni di stile per il disegno, come colore, spessore del tratto e anti-aliasing. Lo crei una sola volta, mai all'interno di onDraw():

class CircleProgressView ... : View(...) {

    // Create Paint in init, not in onDraw!
    private val backgroundPaint = Paint(Paint.ANTI_ALIAS_FLAG).apply {
        color = Color.LTGRAY
        style = Paint.Style.STROKE
        strokeWidth = 20f
        strokeCap = Paint.Cap.ROUND
    }

    private val progressPaint = Paint(Paint.ANTI_ALIAS_FLAG).apply {
        color = Color.parseColor("#6750A4")
        style = Paint.Style.STROKE
        strokeWidth = 20f
        strokeCap = Paint.Cap.ROUND
    }
}

onDraw() — disegno della view

onDraw(canvas) viene chiamato ogni volta che la view deve essere ridisegnata. Utilizzi Canvas per disegnare forme, testo e bitmap:

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

    val cx = width / 2f
    val cy = height / 2f
    val radius = (minOf(width, height) / 2f) - 30f

    // Draw background circle
    canvas.drawCircle(cx, cy, radius, backgroundPaint)

    // Draw progress arc
    val oval = RectF(cx - radius, cy - radius, cx + radius, cy + radius)
    val sweepAngle = 360f * (progress / 100f)
    canvas.drawArc(oval, -90f, sweepAngle, false, progressPaint)
}

invalidate() e requestLayout()

Due metodi per attivare un aggiornamento:

  • invalidate() — ridisegna la view, chiamando onDraw. Lo utilizzi quando cambia il contenuto ma le dimensioni restano uguali.
  • requestLayout() — ricalcola le misure e ridisegna, chiamando prima onMeasure e poi onDraw. Lo utilizzi quando cambiano le dimensioni della view.

Attributi personalizzati (attrs.xml)

Dichiari attributi XML personalizzati per configurare la view dai file di layout:

<!-- res/values/attrs.xml -->
<resources>
    <declare-styleable name="CircleProgressView">
        <attr name="progressColor" format="color" />
        <attr name="trackColor"    format="color" />
        <attr name="strokeWidth"   format="dimension" />
        <attr name="progress"      format="float" />
    </declare-styleable>
</resources>

Lettura degli attributi personalizzati

Legga gli attributi nel costruttore utilizzando obtainStyledAttributes:

init {
    context.obtainStyledAttributes(attrs, R.styleable.CircleProgressView).use { ta ->
        progressPaint.color = ta.getColor(
            R.styleable.CircleProgressView_progressColor,
            Color.parseColor("#6750A4")
        )
        backgroundPaint.color = ta.getColor(
            R.styleable.CircleProgressView_trackColor,
            Color.LTGRAY
        )
        val sw = ta.getDimension(R.styleable.CircleProgressView_strokeWidth, 20f)
        progressPaint.strokeWidth = sw
        backgroundPaint.strokeWidth = sw
        progress = ta.getFloat(R.styleable.CircleProgressView_progress, 0f)
    }
}

Utilizzo della view personalizzata in XML

Utilizzi la view personalizzata nel layout XML con il percorso completo della classe e gli attributi personalizzati:

<!-- In any layout XML -->
<com.example.myapp.CircleProgressView
    android:id="@+id/progressView"
    android:layout_width="120dp"
    android:layout_height="120dp"
    app:progress="65"
    app:progressColor="@color/primary"
    app:trackColor="@color/surface_variant"
    app:strokeWidth="12dp" />

<!-- Control in code: -->
binding.progressView.progress = 75f

Compound View

Una compound view combina view esistenti in un unico componente riutilizzabile. Estenda una classe di layout come LinearLayout:

class SearchBarView @JvmOverloads constructor(
    context: Context, attrs: AttributeSet? = null
) : LinearLayout(context, attrs) {

    private val binding = ViewSearchBarBinding.inflate(LayoutInflater.from(context), this)

    init {
        orientation = HORIZONTAL
        binding.ivSearch.setOnClickListener {
            onSearchClick?.invoke(binding.etSearch.text.toString())
        }
    }

    var onSearchClick: ((String) -> Unit)? = null

    fun setHint(hint: String) { binding.etSearch.hint = hint }
}

Disegno del testo

Disegni il testo su un Canvas con drawText(). Lo centri con precisione utilizzando Paint.getFontMetrics():

private val textPaint = Paint(Paint.ANTI_ALIAS_FLAG).apply {
    color = Color.BLACK
    textSize = 48f
    textAlign = Paint.Align.CENTER
}

override fun onDraw(canvas: Canvas) {
    super.onDraw(canvas)
    val cx = width / 2f
    val cy = height / 2f

    // Vertically center the text:
    val fm = textPaint.fontMetrics
    val textY = cy - (fm.ascent + fm.descent) / 2f
    canvas.drawText("${progress.toInt()}%", cx, textY, textPaint)
}

Verifica rapida

Quale metodo dovrebbe chiamare per ridisegnare la view personalizzata quando cambiano i dati ma le dimensioni restano uguali?

Riepilogo: view personalizzate

Ora può disegnare qualsiasi cosa sullo schermo:

  • Estenda View con @JvmOverloads constructor
  • onMeasure() — comunichi le dimensioni desiderate con setMeasuredDimension()
  • Paint — definisca lo stile; lo crei una sola volta, non all'interno di onDraw()
  • onDraw(canvas) — disegni cerchi, archi, testo e bitmap
  • Utilizzi invalidate() per ridisegnare e requestLayout() per ricalcolare le misure
  • Attributi personalizzati tramite attrs.xml per la configurazione XML
  • Compound view — estenda un layout per combinare view esistenti

Prossimo argomento: dia vita alla UI con animazioni e transizioni.

Domande Frequenti

La lezione «View personalizzate» è gratuita?

Sì — il testo completo di «View personalizzate» è gratuito qui sul web. Per esercitarvi in modo interattivo (un editor di codice integrato e un tutor IA 24/7) e sbloccare il resto del corso Android Academy, passa a CoddyKit PRO. Il corso Android Academy include 5 lezioni in totale.

Cosa imparerò in «View personalizzate»?

Disegni componenti dell'interfaccia personalizzati da zero. Estenda View, implementi onMeasure e onDraw con Canvas e Paint, definisca attributi XML personalizzati e costruisca view composite. Eserciti Android Academy con codice pratico che esegui direttamente nel browser, e un tutor IA 24/7 risponde alle tue domande mentre lavori sulla lezione.

Ho bisogno di esperienza per iniziare Android Academy?

Non è richiesta alcuna esperienza precedente. Android Academy su CoddyKit è strutturato per principianti e studenti avanzati, quindi puoi iniziare da qui o dall'inizio e procedere al tuo ritmo. Questa è la lezione 3 di 5.

Quanto tempo richiede la lezione «View personalizzate»?

La maggior parte delle lezioni CoddyKit richiede circa 5–10 minuti. Ogni lezione è breve e interattiva, quindi fai progressi costanti e riprendi esattamente da dove hai lasciato su web e app.

Posso scrivere ed eseguire codice in questa lezione Android Academy?

Sì. Ogni lezione Android Academy include un editor di codice integrato, quindi scrivi ed esegui codice reale direttamente nel tuo browser e ricevi feedback istantaneo dall'IA — nessuna configurazione locale necessaria.

Tutte le lezioni di questo corso

  1. Nozioni di base di Material Design
  2. Temi e stili
  3. View personalizzate
  4. Animazioni e transizioni
  5. Navigazione inferiore e schede
← Torna a Android Academy