📝

[チュートリアル5]世界各国の時間を表示するアプリを作る[compose multiplatform]

2023/11/09に公開

はじめに

公式ドキュメントの和訳と要約+αです。
前回はこれです。

ページの基本要素を作る

composeApp/src/commonMain/kotlinのApp.ktを開いてください。

現在のコードを消して以下のコードを挿入してください。

@Composable
fun App() {
    MaterialTheme {
        var timeAtLocation by remember { mutableStateOf("No location selected") }
        Column {
            Text(timeAtLocation)
            Button(onClick = {
                timeAtLocation = "13:30"
            }) {
                Text("Show Time At Location")
            }
        }
    }
}

それに伴い以下のimportを挿入してください。

import androidx.compose.foundation.layout.Column
import androidx.compose.material.Button
import androidx.compose.material.MaterialTheme
import androidx.compose.material.Text
import androidx.compose.runtime.Composable
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.setValue

簡単な解説

このレイアウトは、2つのコンポーザブルを含むカラム(列)です。最初のコンポーザブルはテキストで、2つ目はボタンです。

2つのコンポーザブルはtimeAtLocationプロパティを共有して持っています。
テキストコンポーザブルはこの状態のオブザーバー(監視者)なので、timeAtLocationプロパティの中身をリアルタイムで表示しています。
ボタンコンポーザブルはonClickハンドラーを使って、クリックされたらtimeAtLocationの中身に"13:30"を入れています。

ユーザーの入力を受け付けるようにする

ここでの目標は、ユーザーが都市名を入力すると、その場所の時刻が表示されるようにすることです。

そのためにユーザーが入力できるフォームをTextFiledコンポーザブルで実装します。

App.ktを以下の内容に書き換えてください。

@Composable
fun App() {
    MaterialTheme {
        var location by remember { mutableStateOf("Europe/Paris") }
        var timeAtLocation by remember { mutableStateOf("No location selected") }

        Column {
            Text(timeAtLocation)
            TextField(value = location, onValueChange = {
                location = it
            })
            Button(onClick = {
                timeAtLocation = "Time at $location is 13:30"
            }) {
                Text("Show Time At Location")
            }
        }
    }
}

importにはこれを追加してください。

import androidx.compose.material.TextField

簡単なコード解説

TextFieldとlocationプロパティを追加しました。
TextFieldは文字の入力フォームで、onValueChangeイベントハンドラーによって、文字が入力されるとその文字をlocationに代入します。
そのlocationをtimeAtLocationで使って、Textの中とかで使っています。

時間を計算する

ユーザーの入力を使って、表示する時間を計算します。そのためにcurrentTimeAt()というファンクションを作りましょう

currentTimeAt()

App.ktに戻って、以下のコードを追加します。
ファイルの一番下で大丈夫です。

fun currentTimeAt(location: String): String? {
    fun LocalTime.formatted() = "$hour:$minute:$second"

    return try {
        val time = Clock.System.now()
        val zone = TimeZone.of(location)
        val localTime = time.toLocalDateTime(zone).time
        "The time in $location is ${localTime.formatted()}"
    } catch (ex: IllegalTimeZoneException) {
        null
    }
}

それに伴って、以下のimport分も追加しましょう。

import kotlinx.datetime.Clock
import kotlinx.datetime.IllegalTimeZoneException
import kotlinx.datetime.LocalTime
import kotlinx.datetime.TimeZone
import kotlinx.datetime.toLocalDateTime

currentAtTime()を使ってみる

App()コンポーザブルの中で先ほど作ったcurrentTimeAt()を使うように修正しましょう。

App.ktの29行目あたりに、

timeAtLocation = "Time at $location is 13:30"
こういう記述があると思います。
これを以下のように修正してください。

timeAtLocation = currentTimeAt(location) ?: "Invalid Location"

これによって、元々は固定で13:30を表示していたところに、currentTimeAtファンクションにlocationの値を渡した時の返り値を表示するようになります。

元々のチュートリアルはもうちょっとあるんですが、ちょっと長いのでここまで!

残りは次の記事でやります!

Discussion