Android Academy · leksjon

Egendefinerte Views

Tegn egendefinerte brukergrensesnittkomponenter fra grunnen av. Utvid View, implementer onMeasure og onDraw med Canvas og Paint, definer egendefinerte XML-attributter, og bygg sammensatte visninger.

Leksjon 3 av 513 trinn

Egendefinerte Views er en gratis leksjon i Android Academy på CoddyKit. Dette er leksjon 3 av 5. Du kan lese valgfritt 3 leksjoner fra denne læringsstien gratis i sin helhet – deretter låser CoddyKit PRO opp alle leksjoner, samt praktisk øving med en innebygd kodeeditor og en AI-veileder som er tilgjengelig døgnet rundt. Den er en del av læringsløpet i Android Academy, og fremdriften din synkroniseres mellom nettet og CoddyKit-appen. Kurset i Android Academy inneholder totalt 5 leksjoner.

Hvorfor egendefinerte visninger?

Noen ganger gjør de innebygde Android-visningene ikke nøyaktig det De trenger. Egendefinerte visninger lar Dem:

  • Tegne former, grafer, fremdriftsringer eller diagrammer som ikke finnes i SDK-et
  • Opprette profilerte UI-komponenter som brukes konsekvent i hele appen
  • Kombinere flere visninger til én gjenbrukbar komponent (Compound View)
  • Oppnå bedre ytelse ved å fjerne nestede oppsetthierarkier

Utvide View

Opprett en egendefinert visning ved å utvide View (eller en underklasse som ImageView). Overstyr den nødvendige konstruktøren:

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() forteller den overordnede visningen hvor stor denne visningen ønsker å være. Kall alltid setMeasuredDimension() til slutt:

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 — tegneverktøyet

Et Paint-objekt inneholder stilinformasjon for tegning (farge, strekbredde, kantutjevning). Opprett det én gang — aldri inne i 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() — tegne visningen

onDraw(canvas) kalles hver gang visningen må tegnes på nytt. Bruk Canvas til å tegne former, tekst og punktgrafikk:

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

To metoder for å utløse en oppdatering:

  • invalidate() — tegner visningen på nytt (kaller onDraw). Bruk denne når innholdet endres, men størrelsen er den samme.
  • requestLayout() — måler og tegner visningen på nytt (kaller først onMeasure og deretter onDraw). Bruk denne når visningens størrelse endres.

Egendefinerte attributter (attrs.xml)

Definer egendefinerte XML-attributter slik at visningen kan konfigureres fra oppsettsfiler:

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

Lese egendefinerte attributter

Les attrs i konstruktøren ved hjelp av 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)
    }
}

Bruke den egendefinerte visningen i XML

Bruk den egendefinerte visningen i oppsett-XML med full klassenavnesti og egendefinerte attributter:

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

En compound view kombinerer eksisterende visninger til én gjenbrukbar komponent. Utvid en oppsettsklasse som 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 }
}

Tegne tekst

Tegn tekst på et Canvas med drawText(). Sentrer den nøyaktig ved hjelp av 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)
}

Hurtigsjekk

Hvilken metode bør De kalle for å tegne den egendefinerte visningen på nytt når dataene endres, men størrelsen forblir den samme?

Oppsummering: Egendefinerte visninger

De kan nå tegne hva som helst på skjermen:

  • Utvid View med @JvmOverloads constructor
  • onMeasure() — rapporter ønsket størrelse med setMeasuredDimension()
  • Paint — definer stil; opprett én gang, ikke inne i onDraw()
  • onDraw(canvas) — tegn sirkler, buer, tekst og punktgrafikk
  • invalidate() for å tegne på nytt, requestLayout() for å måle på nytt
  • Egendefinerte attributter via attrs.xml for XML-konfigurasjon
  • Compound view — utvid et oppsett for å kombinere eksisterende visninger

Neste: Gjør brukergrensesnittet levende med animasjoner og overganger.

Gratis å komme i gang

Lær deg Kotlin med en AI-veileder – gratis

Skriv og kjør ekte kode i nettleseren, få umiddelbar hjelp fra en AI-veileder som er tilgjengelig døgnet rundt, og fortsett der du slapp – på nettet eller i appen.

Kurs
36
Leksjoner
152

Ofte stilte spørsmål

Er leksjonen «Egendefinerte Views» gratis?

Ja – du kan lese valgfritt 3 av leksjonene i læringsstien Android Academy, inkludert «Egendefinerte Views», gratis i sin helhet her på nettet. Deretter låser CoddyKit PRO opp alle leksjoner, samt interaktiv øving med en innebygd kodeeditor og en AI-veileder som er tilgjengelig døgnet rundt. Kurset i Android Academy inneholder totalt 5 leksjoner.

Hva lærer jeg i «Egendefinerte Views»?

Tegn egendefinerte brukergrensesnittkomponenter fra grunnen av. Utvid View, implementer onMeasure og onDraw med Canvas og Paint, definer egendefinerte XML-attributter, og bygg sammensatte visninger. Du øver på Android Academy med praktisk kode som du kjører direkte i nettleseren, mens en AI-veileder som er tilgjengelig døgnet rundt, svarer på spørsmålene dine mens du jobber deg gjennom leksjonen.

Trenger jeg erfaring for å begynne med Android Academy?

Ingen tidligere erfaring er nødvendig. Android Academy på CoddyKit er lagt opp for både nybegynnere og viderekomne, så De kan begynne her eller helt fra start og lære i Deres eget tempo. Dette er leksjon 3 av 5.

Hvor lang tid tar leksjonen «Egendefinerte Views»?

De fleste CoddyKit-leksjoner tar omtrent 5–10 minutter. Hver leksjon er kort og interaktiv, slik at De gjør jevne fremskritt og kan fortsette akkurat der De slapp – både på nettet og i appen.

Kan jeg skrive og kjøre kode i denne Android Academy-leksjonen?

Ja. Alle Android Academy-leksjoner har en innebygd kodeeditor, slik at De kan skrive og kjøre ekte kode direkte i nettleseren og få umiddelbar tilbakemelding fra AI – uten lokal konfigurering.

Alle leksjonene i dette kurset

  1. Grunnleggende Material Design
  2. Temaer og stiler
  3. Egendefinerte Views
  4. Animasjoner og overganger
  5. Bunnnavigasjon og faner
← Tilbake til Android Academy