Jeg har vært på flere app-prosjekter uten å bli eksponert for radio buttons. Mulig det ikke er så utbredt i app-verden, eller at designere på de prosjektene ikke syntes de var noe særlig. Uansett, jeg kom over et kurs for Android-sertifisering, og en av oppgavene har radio buttons, yay! Ved å følge instruksjonene i oppgaven lager man en enkel tip calculator app som ser sånn ut:
Vi lager en RadioGroup inne i activity_main.xml
, og legger på RadioButtons - so far so good. Deretter går til onCreate
i MainActivity.kt
, legger på en click listener for calculate knappen. Derfra får vi tak i checkedRadioButtonId
, og legger på en when
statement for hva slags id som er valgt:
val checkedId = findViewById<RadioGroup>(R.id.tip_options).checkedRadioButtonId
val tipPercentage = when (checkedId) {
R.id.option_twenty_percent -> 0.20
R.id.option_eighteen_percent -> 0.18
else -> 0.15
}
Wait.. what?
Her itererer vi over alle mulige id’ene for radioknapper i gruppen og manuelt setter en verdi som checkedRadioButton
representerer - altså prosent. Dette virker tungvint. Hvorfor sjekker vi ikke bare på verdien til den valgte radioknappen? Går inn i layout editor og trippeltsjekker alle attributter på radio button for å finne value
eller lignende jeg kan sette. Den finnes ikke?
Mulig jeg har vært for lenge på web-prosjekter. Hvorfor har ikke radio buttons mulighet for å sette en verdi? Nei, dette var irriterende, må jo ha en value
man kan sende inn på en radio button?!
¶Custom radio button
Løsningen her ble å lage en custom radio button.
class CustomRadioButton(context: Context?, attrs: AttributeSet?) :
AppCompatRadioButton(context, attrs) {
}
Foreløpig speiler den bare den eksisterende implementasjonen av vanlig radio button. Neste steg er å få den til å ha value
som attributt. Under values
mappen, legger jeg inn en ny fil attrs.xml
og deklarerer en ny value
som en string attributt, knyttet til styleables for vår nye CustomRadioButton.
<?xml version="1.0" encoding="utf-8"?>
<resources>
<declare-styleable name="CustomRadioButton">
<attr name="value" format="string" />
</declare-styleable>
</resources>
og whoosh, nå kan vi sette verdi på custom radio button:
<com.example.tiptime.CustomRadioButton
android:id="@+id/option_twenty_percent"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/amazing_20"
app:value="20"/>
Dette var gøy! Men, hvordan kan vi nå få tak i verdien på radio button fra koden? La oss teste direkte i MainActivity.kt
:
val checkedId = findViewById<RadioGroup>(R.id.tip_options).checkedRadioButtonId
val checked = findViewById<CustomRadioButton>(checkedId)
val checkedValue = checked.value
Det gikk ikke, vi får kompileringsfeil og den banner på oss med Unresolved reference: value
. Vi må eksponere value
på noe vis.
Tilbake i CustomRadioButton.kt
, utvider klassen med:
class CustomRadioButton(context: Context?, attrs: AttributeSet?) :
AppCompatRadioButton(context, attrs) {
var value: String = ""
init {
val typedArray = context?.theme?.obtainStyledAttributes(attrs, R.styleable.CustomRadioButton,
0, 0)
value = typedArray?.getString(R.styleable.CustomRadioButton_value).toString()
typedArray?.recycle()
}
}
Her deklarerer vi value
, henter alle styleables på init
, og tilegner value
til å være den som ble satt i XML-deklarasjonen vår. Til slutt må array med styleables frigjøres siden det er en delt ressurs.
¶Hva har vi lært?
- At radio buttons i Android ikke har innebygd støtte for å sette verdi
- At det går an å gjøre noe med det
- At det blir mer kode av det (med mindre det er snakk om en radio button group med en hel haug radio buttons, men da bør man kanskje revurdere designet.. 😅)
¶Konklusjon
Dette var et morsomt tanke- og kodeeksperiment. Kommer jeg til å bruke custom radio buttons kun for å fiske ut verdi istedenfor en brute-force id-sjekk? Sansynligvis ikke. Men dersom man uansett skal lage en egen komponent for radio button for å utvide med mer funksjonalitet, så er det fort gjort å slenge på en value
som supplement.