0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

チップを計算するアプリを作ってみる。

Posted at

参考にした場所

引用:UIと状態

スターター コードを取得を入手する。

github
$ git clone https://github.com/google-developer-training/basic-android-kotlin-compose-training-tip-calculator.git
$ cd basic-android-kotlin-compose-training-tip-calculator
$ git checkout starter

入手したら展開して起動します。

チップアプリで用いる単語をstring.xmlに登録します。

res -> values -> string.xml

string.xml
<resources>
   <string name="app_name">Tip Time</string>
   <string name="calculate_tip">Calculate Tip</string>
   <string name="bill_amount">Bill Amount</string>
   <string name="tip_amount">Tip Amount: %s</string>
</resources>

テキストフィールドを作る。

スターターコードはある程度書いてあるので、その次からやっていきます。

テキストフィールドコンポーザブルを作ります。

MainActivity.kt
@Composable
fun EditNumberField(modifier: Modifier=Modifier){
    TextField(value = "", onValueChange = {},modifier=modifier)

}

これをTipTimeLayout()に入れます。

MainActivity.kt
    Text()
    EditNumberField(modifier = Modifier
        .padding(bottom = 36.dp)
        .fillMaxWidth())
    Text()

Composeで状態を使用する。

状態とは時間と共に変化する可能性があるものを指します。
テキストフィールドの状態を最初0にします。

MainActivity.kt
@Composable
fun EditNumberField(modifier: Modifier=Modifier){
    val amountInput = "0"
    TextField(value = amountInput , onValueChange = {},modifier=modifier)
}

構成

変化する可能性のある値を監視するためにmutableStateOf()関数を使います。

また警告が出るために無視します。

MainActivity.kt
import androidx.compose.runtime.MutableState
import androidx.compose.runtime.mutableStateOf

@SuppressLint("UnrememberedMutableState")
@Composable
fun EditNumberField(modifier: Modifier=Modifier){
    var amountInput = mutableStateOf("0")
    TextField(value = amountInput.value,
        onValueChange = {amountInput.value = it},
        modifier=modifier)
}

onValueChange コールバックはテキストボックスへの入力が変更されるとトリガーされます。

この状態でアプリを起動して、テキストフィールドに入力しても文字は保存されません

remember 関数を使用して状態を保存する

再コンポーズにより、コンポーズ可能なメソッドが何度も呼び出される場合があります。コンポーザブルは、保存されていない場合、再コンポーズ中に状態をリセットします。

そのため、保存する値がある場合、一時的に格納する必要があります。
remember関数を使います。

MainActivity.kt
import androidx.compose.runtime.remember
import androidx.compose.runtime.getValue
import androidx.compose.runtime.setValue

@Composable
fun EditNumberField(modifier: Modifier = Modifier) {
   var amountInput by remember { mutableStateOf("") }
   TextField(
       value = amountInput,
       onValueChange = { amountInput = it },
       modifier = modifier
   )
}

これで保存されるようになりました。

外観を変更する

テキスト ボックスにラベルを追加する

追加するのはラベル、下線、キーボード タイプの制限です。

MainActivity.kt
import androidx.compose.foundation.text.KeyboardOptions
import androidx.compose.ui.text.input.KeyboardType


@Composable
fun EditNumberField(modifier: Modifier = Modifier) {
    var amountInput by remember { mutableStateOf("") }
    TextField(
        value = amountInput,
        onValueChange = { amountInput = it },
        singleLine = true,
        label = { Text(stringResource(R.string.bill_amount)) },
        keyboardOptions = KeyboardOptions(keyboardType = KeyboardType.Number),
        modifier = modifier
    )
}

チップの金額を表示する

スターター コードの一部として提供されている private calculateTip()を用います。

テキストフィールドに入力された値はStringなのでDoubleに変更します。

使うのは toDoubleOrNull 関数です。

MainActivity.kt
@Composable
fun EditNumberField(modifier: Modifier = Modifier) {

    var amountInput by remember { mutableStateOf("") }
    val amount = amountInput.toDoubleOrNull() ?: 0.0
    val tip = calculateTip(amount)


    TextField(
        value = amountInput,
        onValueChange = { amountInput = it },
        modifier = modifier,
        singleLine = true,
        label = { Text(text = stringResource(id = R.string.bill_amount))},
        keyboardOptions = KeyboardOptions(keyboardType = KeyboardType.Number)
    )
}

次にここで計算されたtipを表示する必要があります。
このコンポーザブルの値を別のコンポーザブルから巻き上げ、ホイスティングします。
入力したと同時に行う、つまりステートレスにもします。

状態ホイスティング

状態を他のコンポーザブルで利用できるするためにvalue パラメータと onValueChange パラメータを追加して状態をホイスティングします。

MainActivity.kt

@Composable
fun EditNumberField(
   value: String,
   onValueChange: (String) -> Unit,
   modifier: Modifier = Modifier
) {
//...

TextField(
   value = value,
   onValueChange = onValueChange,
   //...
)

そしてremember で保存した状態を EditNumberField() 関数から TipTimeLayout() 関数に移動します。

MainActivity.kt

@Composable
fun TipTimeLayout() {
   var amountInput by remember { mutableStateOf("") }

   val amount = amountInput.toDoubleOrNull() ?: 0.0
   val tip = calculateTip(amount)

   Column(
       //...
   ) {
       //...
   }
}

状態ホイスティングにより、テキストフィールドに入力された値が、すべてつながるようになりました。

状態ホイスティングを行うために、コンポーズ可能な関数 EditNumberField() に amountInput 値と、ユーザーの入力によって amountInput 値を更新するラムダ コールバックの 2 つの引数を渡しました。

完成がこちらです

MainActivity.kt

@Composable
fun TipTimeLayout() {
   var amountInput by remember { mutableStateOf("") }
   val amount = amountInput.toDoubleOrNull() ?: 0.0
   val tip = calculateTip(amount)

   Column(
       modifier = Modifier
            .statusBarsPadding()
            .padding(horizontal = 40.dp)
            .verticalScroll(rememberScrollState())
            .safeDrawingPadding(),
       horizontalAlignment = Alignment.CenterHorizontally,
       verticalArrangement = Arrangement.Center
   ) {
       Text(
           text = stringResource(R.string.calculate_tip),
           modifier = Modifier
               .padding(bottom = 16.dp, top = 40.dp)
               .align(alignment = Alignment.Start)
       )
       EditNumberField(
           value = amountInput,
           onValueChange = { amountInput = it },
           modifier = Modifier
               .padding(bottom = 32.dp)
               .fillMaxWidth()
       )
       Text(
           text = stringResource(R.string.tip_amount, tip),
           style = MaterialTheme.typography.displaySmall
       )
       Spacer(modifier = Modifier.height(150.dp))
   }
}

@Composable
fun EditNumberField(
   value: String,
   onValueChange: (String) -> Unit,
   modifier: Modifier = Modifier
) {
   TextField(
       value = value,
       onValueChange = onValueChange,
       singleLine = true,
       label = { Text(stringResource(R.string.bill_amount)) },
       keyboardOptions = KeyboardOptions(keyboardType = KeyboardType.Number),
       modifier = modifier
   )
}

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?