0Pricing
Android Academy · Leçon

Vues personnalisées

Dessinez des composants d’interface personnalisés à partir de zéro. Étendez View, implémentez onMeasure et onDraw avec Canvas et Paint, définissez des attributs XML personnalisés et créez des vues composites.

Vues personnalisées est une leçon Android Academy gratuite sur CoddyKit. Ceci est la leçon 3 sur 5. Tu peux lire la leçon complète ci-dessous gratuitement — puis la pratiquer en direct dans le navigateur avec un éditeur de code intégré et un tuteur IA 24/7. Elle fait partie du parcours d'apprentissage Android Academy, et ta progression se synchronise sur le web et l'application CoddyKit. Le cours Android Academy comprend 5 leçons au total.

Pourquoi créer des vues personnalisées ?

Parfois, les vues Android intégrées ne font pas exactement ce dont vous avez besoin. Les vues personnalisées vous permettent de :

  • Dessiner des formes, graphiques, anneaux de progression ou diagrammes qui n'existent pas dans le SDK
  • Créer des composants d'interface de marque utilisés de manière cohérente dans toute l'application
  • Combiner plusieurs vues en un seul composant réutilisable (vue composée)
  • Améliorer les performances en supprimant les hiérarchies de mises en page imbriquées

Étendre View

Créez une vue personnalisée en étendant View (ou une sous-classe comme ImageView). Remplacez le constructeur requis :

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() indique au parent quelle taille cette vue souhaite avoir. Appelez toujours setMeasuredDimension() à la fin :

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 — l'outil de dessin

Un objet Paint contient les informations de style nécessaires au dessin (couleur, largeur du contour, anticrénelage). Créez-le une seule fois — jamais dans 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() — dessiner la vue

onDraw(canvas) est appelée chaque fois que la vue doit être redessinée. Utilisez le Canvas pour dessiner des formes, du texte et des bitmaps :

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() et requestLayout()

Deux méthodes permettent de déclencher une mise à jour :

  • invalidate() — redessine la vue (appelle onDraw). Utilisez-la lorsque le contenu change mais que la taille reste identique.
  • requestLayout() — mesure et redessine la vue (appelle d'abord onMeasure, puis onDraw). Utilisez-la lorsque la taille de la vue change.

Attributs personnalisés (attrs.xml)

Déclarez des attributs XML personnalisés afin de configurer la vue depuis les fichiers de mise en page :

<!-- 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>

Lire les attributs personnalisés

Lisez les attributs dans le constructeur à l'aide de 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)
    }
}

Utiliser la vue personnalisée en XML

Utilisez votre vue personnalisée dans le XML de mise en page avec le chemin complet de la classe et les attributs personnalisés :

<!-- 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

Vues composées

Une vue composée combine des vues existantes en un seul composant réutilisable. Étendez une classe de mise en page comme 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 }
}

Dessiner du texte

Dessinez du texte sur un Canvas avec drawText(). Centrez-le précisément à l'aide de 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)
}

Vérification rapide

Quelle méthode devez-vous appeler pour redessiner votre vue personnalisée lorsque les données changent mais que la taille reste identique ?

Récapitulatif : vues personnalisées

Vous pouvez maintenant tout dessiner à l'écran :

  • Étendez View avec @JvmOverloads constructor
  • onMeasure() — indiquez la taille souhaitée avec setMeasuredDimension()
  • Paint — définissez le style ; créez l'objet une seule fois, et non dans onDraw()
  • onDraw(canvas) — dessinez des cercles, des arcs, du texte et des bitmaps
  • invalidate() pour redessiner, requestLayout() pour effectuer une nouvelle mesure
  • Attributs personnalisés via attrs.xml pour la configuration XML
  • Vue composée — étendez une mise en page pour combiner des vues existantes

Ensuite : donnez vie à votre interface avec les animations et les transitions.

Questions Fréquemment Posées

La leçon « Vues personnalisées » est-elle gratuite ?

Oui — le texte complet de « Vues personnalisées » est gratuit à lire ici sur le web. Pour la pratiquer de manière interactive (un éditeur de code intégré et un tuteur IA 24/7) et déverrouiller le reste du cours Android Academy, passe à CoddyKit PRO. Le cours Android Academy comprend 5 leçons au total.

Qu'est-ce que j'apprendrai dans « Vues personnalisées » ?

Dessinez des composants d’interface personnalisés à partir de zéro. Étendez View, implémentez onMeasure et onDraw avec Canvas et Paint, définissez des attributs XML personnalisés et créez des vues co… Tu pratiques Android Academy avec du code pratique que tu exécutes directement dans le navigateur, et un tuteur IA 24/7 répond à tes questions au fur et à mesure que tu avances dans la leçon.

Dois-je avoir de l'expérience pour commencer Android Academy ?

Aucune expérience préalable n'est requise. Android Academy sur CoddyKit est structuré pour les débutants jusqu'aux apprenants avancés, donc tu peux commencer ici ou depuis le début et avancer à ton rythme. Ceci est la leçon 3 sur 5.

Combien de temps prend la leçon « Vues personnalisées » ?

La plupart des leçons CoddyKit prennent environ 5–10 minutes. Chacune est courte et interactive, tu progresses régulièrement et tu repiques exactement où tu t'es arrêté sur le web et l'app.

Peux-tu écrire et exécuter du code dans cette leçon Android Academy ?

Oui. Chaque leçon Android Academy inclut un éditeur de code intégré, tu écris et exécutes du vrai code directement dans ton navigateur et tu reçois des retours IA instantanés — aucune configuration locale requise.

Toutes les leçons de ce cours

  1. Notions de base de Material Design
  2. Thèmes et styles
  3. Vues personnalisées
  4. Animations et transitions
  5. Navigation inférieure et onglets
← Retour à Android Academy