0Pricing
Android Academy · Lektion

Benutzerdefinierte Views

Zeichnen Sie benutzerdefinierte UI-Komponenten von Grund auf. Erweitern Sie View, implementieren Sie onMeasure und onDraw mit Canvas und Paint, definieren Sie benutzerdefinierte XML-Attribute und erstellen Sie zusammengesetzte Views.

Benutzerdefinierte Views ist eine kostenlose Android Academy-Lektion auf CoddyKit. Dies ist Lektion 3 von 5. Du kannst die komplette Lektion unten kostenlos lesen – dann übst du sie direkt im Browser mit einem integrierten Code-Editor und einem KI-Tutor rund um die Uhr. Sie ist Teil des Android Academy-Lernpfads, und dein Fortschritt wird über Web und CoddyKit-App synchronisiert. Der Android Academy-Kurs umfasst insgesamt 5 Lektionen.

Warum benutzerdefinierte Views?

Manchmal bieten die integrierten Android-Views nicht genau die benötigten Funktionen. Mit benutzerdefinierten Views können Sie:

  • Formen, Diagramme, Fortschrittsringe oder andere im SDK nicht vorhandene Elemente zeichnen
  • Markenspezifische UI-Komponenten erstellen, die in der gesamten App konsistent verwendet werden
  • Mehrere Views zu einer wiederverwendbaren Komponente kombinieren (Compound View)
  • Durch das Vermeiden verschachtelter Layout-Hierarchien eine bessere Performance erzielen

View erweitern

Erstellen Sie eine benutzerdefinierte View, indem Sie View (oder eine Unterklasse wie ImageView) erweitern. Überschreiben Sie den erforderlichen Konstruktor:

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() teilt dem übergeordneten Element mit, wie groß diese View sein möchte. Rufen Sie am Ende immer setMeasuredDimension() auf:

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 — das Zeichenwerkzeug

Ein Paint-Objekt enthält die Stilinformationen zum Zeichnen (Farbe, Strichbreite, Anti-Aliasing). Erstellen Sie es einmal — niemals innerhalb von 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() — die View zeichnen

onDraw(canvas) wird jedes Mal aufgerufen, wenn die View neu gezeichnet werden muss. Verwenden Sie den Canvas, um Formen, Text und Bitmaps zu zeichnen:

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() und requestLayout() im Vergleich

Zwei Methoden, um eine Aktualisierung auszulösen:

  • invalidate() — zeichnet die View neu (ruft onDraw auf). Verwenden Sie die Methode, wenn sich der Inhalt ändert, die Größe aber gleich bleibt.
  • requestLayout() — misst die View neu und zeichnet sie erneut (ruft zuerst onMeasure und dann onDraw auf). Verwenden Sie die Methode, wenn sich die Größe der View ändert.

Benutzerdefinierte Attribute (attrs.xml)

Definieren Sie benutzerdefinierte XML-Attribute, damit die View über Layout-Dateien konfiguriert werden kann:

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

Benutzerdefinierte Attribute auslesen

Lesen Sie attrs im Konstruktor mit obtainStyledAttributes aus:

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)
    }
}

Benutzerdefinierte View in XML verwenden

Verwenden Sie Ihre benutzerdefinierte View im Layout-XML mit dem vollständigen Klassenpfad und den benutzerdefinierten Attributen:

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

Eine Compound View kombiniert vorhandene Views zu einer wiederverwendbaren Komponente. Erweitern Sie eine Layout-Klasse wie 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 }
}

Text zeichnen

Zeichnen Sie Text mit drawText() auf einem Canvas. Zentrieren Sie ihn mithilfe von Paint.getFontMetrics() präzise:

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)
}

Kurze Überprüfung

Welche Methode sollten Sie aufrufen, um Ihre benutzerdefinierte View neu zu zeichnen, wenn sich die Daten ändern, die Größe aber gleich bleibt?

Zusammenfassung: Benutzerdefinierte Views

Sie können jetzt beliebige Elemente auf dem Bildschirm zeichnen:

  • View mit @JvmOverloads constructor erweitern
  • onMeasure() — die gewünschte Größe mit setMeasuredDimension() melden
  • Paint — den Stil festlegen; einmal erstellen, nicht innerhalb von onDraw()
  • onDraw(canvas) — Kreise, Bögen, Text und Bitmaps zeichnen
  • invalidate() zum Neuzeichnen, requestLayout() zum erneuten Messen
  • Benutzerdefinierte Attribute über attrs.xml zur Konfiguration per XML
  • Compound View — ein Layout erweitern, um vorhandene Views zu kombinieren

Als Nächstes: Erwecken Sie Ihre UI mit Animationen und Übergängen zum Leben.

Häufig gestellte Fragen

Ist die Lektion „Benutzerdefinierte Views“ kostenlos?

Ja — der vollständige Text von „Benutzerdefinierte Views“ ist hier im Web kostenlos zu lesen. Um sie interaktiv zu üben (integrierter Code-Editor und 24/7 KI-Tutor) und den Rest des Android Academy-Kurses freizuschalten, upgrade auf CoddyKit PRO. Der Android Academy-Kurs umfasst insgesamt 5 Lektionen.

Was lerne ich in „Benutzerdefinierte Views“?

Zeichnen Sie benutzerdefinierte UI-Komponenten von Grund auf. Erweitern Sie View, implementieren Sie onMeasure und onDraw mit Canvas und Paint, definieren Sie benutzerdefinierte XML-Attribute und ers… Du übst Android Academy mit praktischem Code, den du direkt im Browser ausführst, und ein 24/7 KI-Tutor beantwortet deine Fragen während du die Lektion bearbeitest.

Brauche ich Erfahrung, um Android Academy zu starten?

Keine Vorkenntnisse erforderlich. Android Academy auf CoddyKit ist für Anfänger bis fortgeschrittene Lernende strukturiert, sodass du hier starten oder von Anfang an beginnen und in deinem eigenen Tempo voranschreiten kannst. Dies ist Lektion 3 von 5.

Wie lange dauert die Lektion „Benutzerdefinierte Views“?

Die meisten CoddyKit-Lektionen dauern etwa 5–10 Minuten. Jede ist kompakt und interaktiv, sodass du stetig Fortschritte machst und genau dort weitermachst, wo du aufgehört hast – im Web und in der App.

Kann ich in dieser Android Academy-Lektion Code schreiben und ausführen?

Ja. Jede Android Academy-Lektion enthält einen integrierten Code-Editor, sodass du echten Code direkt in deinem Browser schreibst und ausführst und sofort KI-Feedback erhältst — ohne lokale Einrichtung erforderlich.

Alle Lektionen in diesem Kurs

  1. Grundlagen von Material Design
  2. Themes und Styles
  3. Benutzerdefinierte Views
  4. Animationen und Übergänge
  5. Untere Navigation und Tabs
← Zurück zu Android Academy