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

カスタムのチップ金額を計算する

参考URL

前回の続きからです。

最初に今回使うStringを登録します。

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>
    <string name="how_was_the_service">Tip Percentage</string>
    <string name="round_up_tip">Round up tip?</string>
</resources>

チップ率を変更するためのテキストフィールドを作ります。
そのために前回使用したテキストフィールドコンポーザブルを使いますが、区別をつけるためにlabelを追加します。

MainActivity.kt
@Composable
fun EditNumberField(
    label: Int,
    value: String,
    onValueChanged: (String) -> Unit,
    modifier: Modifier = Modifier
)

関数本体の方もハードコードされた文字列をlabelに変更します。

MainActivity.kt
@Composable
fun EditNumberField(
    //...
) {
     TextField(
         //...
         label = { Text(stringResource(label)) },
         //...
     )
}

このままでは参照の型がおかしいと表示されるのでアノテーションを付け加えます。

MainActivity.kt
import androidx.annotation.StringRes

@Composable
fun EditNumberField(
    @StringRes label: Int,
    value: String,
    onValueChanged: (String) -> Unit,
    modifier: Modifier = Modifier
)

そして関数本体にあるEditNumberField()のlabelを変更します。

MainActivity.kt
EditNumberField(
    label = R.string.bill_amount,
    value = amountInput,
    onValueChanged = { amountInput = it },
    modifier = Modifier.padding(bottom = 32.dp).fillMaxWidth()
)

今回の目的のチップのパーセンテージをカスタムするテキストフィールドを作ります

MainActivity.kt
EditNumberField(
    label = R.string.how_was_the_service,
    value = "",
    onValueChanged = { },
    modifier = Modifier.padding(bottom = 32.dp).fillMaxWidth()
)

このフィールドへの入力を格納するための変数をTipTimeLayoutに追加します。

MainActivity.kt
fun TipTimeLayout() {
    var amountInput by remember { mutableStateOf("") }
    var tipInput by remember { mutableStateOf("") }
    val amount = amountInput.toDoubleOrNull() ?: 0.0

追加した変数をテキストフィールドにも適応させます

MainActivity.kt
EditNumberField(
    label = R.string.how_was_the_service,
    value = tipInput,
    onValueChanged = { tipInput = it },
    modifier = Modifier.padding(bottom = 32.dp).fillMaxWidth()
)

その後前回のamountInputに適応したdoubleへの変更処理とtipPercentをtipに適応させます。

MainActivity.kt
@Composable
fun TipTimeLayout() {
    var amountInput by remember { mutableStateOf("") }
    var tipInput by remember { mutableStateOf("") }
    val amount = amountInput.toDoubleOrNull() ?: 0.0
    val tipPercent = tipInput.toDoubleOrNull() ?: 0.0

    val tip = calculateTip(amount, tipPercent)
    Column(
        modifier = Modifier.padding(40.dp),
        horizontalAlignment = Alignment.CenterHorizontally,
        verticalArrangement = Arrangement.Center
    ) {
        Text(
            text = stringResource(R.string.calculate_tip),
            modifier = Modifier
                .padding(bottom = 16.dp)
                .align(alignment = Alignment.Start)
        )
        EditNumberField(
            label = R.string.bill_amount,
            value = amountInput,
            onValueChanged = { amountInput = it },
            modifier = Modifier
                .padding(bottom = 32.dp)
                .fillMaxWidth()
        )
        EditNumberField(
            label = R.string.how_was_the_service,
            value = tipInput,
            onValueChanged = { tipInput = 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))
    }
}

アクション ボタンを設定する

キーボードオプションKeyboardOptionsを使って、キーボードをカスタムします。

今回は決定のボタンをNextとDoneに割り振ります。

MainActivity.kt

EditNumberField(value = amountInput,
            label = R.string.bill_amount,
            onValueChange = { amountInput = it },
            modifier = Modifier
                .padding(bottom = 36.dp)
                .fillMaxWidth(),
            keyboardOptions = KeyboardOptions(
                keyboardType = KeyboardType.Number,
                imeAction = ImeAction.Next)
        )
        EditNumberField(value = tipInput,
            label = R.string.how_was_the_service,
            onValueChange = { tipInput = it },
            modifier = Modifier
                .padding(bottom = 36.dp)
                .fillMaxWidth(),
            keyboardOptions = KeyboardOptions(
                keyboardType = KeyboardType.Number,
                imeAction = ImeAction.Done)
        )

//...

@Composable
fun EditNumberField(value: String,
                    @StringRes label:Int,
                    onValueChange: (String) -> Unit,
                    modifier: Modifier = Modifier,
                    keyboardOptions: KeyboardOptions = KeyboardOptions()) {

    TextField(
        value = value,
        onValueChange = onValueChange,
        modifier = modifier,
        singleLine = true,
        label = { Text(text = stringResource(label))},
        keyboardOptions = keyboardOptions,

    )
}

スイッチを追加する

チップを整数に切り上げるスイッチを付け加えます。

左に説明文、右にスイッチがあるコンポーザブルを作ります。

説明文はString.xmlから取得します。

新しいパラメータとしてスイッチの状態を示すroundUpとコールバック関数のonRoundUpChangedを追加します。
スイッチを右端に置きます。

MainActivity.kt
@Composable
fun RoundTheTipRow(roundUp:Boolean,
                   onRoundUpChanged:(Boolean) ->(Unit),
                   modifier: Modifier= Modifier){
    Row(modifier = modifier
        .fillMaxWidth()
        .size(48.dp),
        verticalAlignment = Alignment.CenterVertically) {
        Text(text = stringResource(id = R.string.round_up_tip))
        Switch(checked = roundUp, onCheckedChange = onRoundUpChanged,
            modifier = modifier.fillMaxWidth().wrapContentWidth(Alignment.End))
    }
}

関数本体も変更します。

MainActivity.kt
@Composable
fun TipTimeLayout() {
    //...
    var roundUp by remember { mutableStateOf(false) }
    //...

    Column(
        ...
    ) {
        Text(
            ...
        )
        Spacer(...)
        EditNumberField(
            ...
        )
        EditNumberField(
            ...
        )
        RoundTheTipRow(
             roundUp = roundUp,
             onRoundUpChanged = { roundUp = it },
             modifier = Modifier.padding(bottom = 32.dp)
         )
        Text(
            ...
        )
    }
}

今度はcalculateTipに修正を加えます。

MainActivity.kt
fun TipTimeLayout() {
//...
    val tipPercent = tipInput.toDoubleOrNull() ?: 0.0
    val tip = calculateTip(amount,tipPercent,roundUp)
    //...
}

private fun calculateTip(amount: Double, tipPercent: Double = 15.0,roundUp: Boolean): String {
    var tip = tipPercent / 100 * amount
    if(roundUp){tip = kotlin.math.ceil(tip)}
    return NumberFormat.getCurrencyInstance().format(tip)
}

これでスイッチの完成です。

横向きのサポートを追加する

横向きだとしたの画面が表示されない可能性があるのでスクロール機能を付けます。

付け加えるのは修飾子のverticalScroll(rememberScrollState())です。

MainActivity.kt
fun TipTimeLayout() {
//...
    Column(
        modifier = Modifier
            .statusBarsPadding()
            .padding(horizontal = 40.dp)
            .safeDrawingPadding().verticalScroll(rememberScrollState()),
        horizontalAlignment = Alignment.CenterHorizontally,
        verticalArrangement = Arrangement.Center
    )
//...

これで横向きにしても画面をスクロールして見れるようになりました。

テキスト フィールドに先頭のアイコンを追加する(省略可)

テキストフィールドにアイコンを付け加えて視覚的に理解しやすくします。
leadingIconを付け加えます。

MainActivity.kt
@Composable
fun EditNumberField(value: String,
                    @StringRes label:Int,
                    @DrawableRes leadingIcon:Int,
                    onValueChange: (String) -> Unit,
                    modifier: Modifier = Modifier,
                    keyboardOptions: KeyboardOptions = KeyboardOptions()) {

    TextField(
        value = value,
        leadingIcon = { Icon(painter = painterResource(id = leadingIcon),
            contentDescription = null)},
        onValueChange = onValueChange,
        modifier = modifier,
        singleLine = true,
        label = { Text(text = stringResource(label))},
        keyboardOptions = keyboardOptions,

    )
}
//...
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?