はじめに
Jetpack Compose で入力フォームを作成する方法を記載します。画面に配置する要素は3つで、メールアドレス入力欄、パスワード入力欄、ボタンです。
Empty Compose Activity から作り始めた場合、おそらく追加のパッケージは必要ありません。
実装
まずはメールアドレス入力欄の実装です。
@Composable
fun EmailTextField(
value: String,
modifier: Modifier = Modifier,
onValueChange: (String) -> Unit,
) {
val focusManager = LocalFocusManager.current
OutlinedTextField(
value = value,
onValueChange = onValueChange,
modifier = modifier,
keyboardOptions = KeyboardOptions(
keyboardType = KeyboardType.Email,
imeAction = ImeAction.Next,
),
keyboardActions = KeyboardActions(
onNext = {
focusManager.moveFocus(FocusDirection.Down)
}
),
label = { Text("メールアドレス") },
)
}
keyboardType = KeyboardType.Email
とすることで、キーボードがメールアドレスの入力用になります。
ImeAction.Next
はキーボードの右下にあるボタンの形式を表します。keyboardOptions
の imeAction = ImeAction.XXX
と keyboardActions
の onXXX
は密接に関係しており、たとえば imeAction = ImeAction.Next
と設定すると onNext
で渡した関数が呼ばれます。
focusManager.moveFocus(FocusDirection.Down)
により次のフォーカス先にフォーカスを移すことができます。
次はパスワード入力欄の実装です。
@Composable
fun PasswordTextField(
value: String,
modifier: Modifier = Modifier,
onValueChange: (String) -> Unit,
submit: () -> Unit,
) {
val focusManager = LocalFocusManager.current
OutlinedTextField(
value = value,
onValueChange = onValueChange,
modifier = modifier,
keyboardOptions = KeyboardOptions(
keyboardType = KeyboardType.Password,
imeAction = ImeAction.Done,
),
keyboardActions = KeyboardActions(
onDone = {
focusManager.clearFocus()
submit()
}
),
visualTransformation = PasswordVisualTransformation(),
label = { Text("パスワード") },
)
}
今回はキーボードで決定を押すと submit 処理が走ってほしいため、submit 関数を受け取るようにしています。
メールアドレス入力欄とほぼ同じですが、visualTransformation = PasswordVisualTransformation()
という見慣れない記述があります。これは、パスワードを非表示にする変換処理を登録しています。
最後にボタンの実装です。
@Composable
fun LoginButton(
ajax: Boolean,
modifier: Modifier = Modifier,
submit: () -> Unit,
) {
Button(onClick = submit, enabled = !ajax, modifier = modifier) {
if (ajax) {
CircularProgressIndicator(
strokeWidth = 2.dp,
modifier = Modifier.size(24.dp)
)
} else {
Text("ログイン")
}
}
}
処理中はボタンイベントを無効にしたいため enabled = !ajax
としています。
これらの要素を取り入れたフォームの実装は次のようになります。
@Composable
fun LoginForm() {
var ajax by remember { mutableStateOf(false) }
var email by remember { mutableStateOf("") }
var password by remember { mutableStateOf("") }
val scope = rememberCoroutineScope()
val submit = {
scope.launch(Dispatchers.IO) {
ajax = true
// ここにログイン処理を記述する
ajax = false
}
Unit
}
Column(
modifier = Modifier
.fillMaxSize()
.padding(16.dp)
) {
EmailTextField(email, Modifier.fillMaxWidth()) { email = it }
Spacer(Modifier.height(4.dp))
PasswordTextField(password, Modifier.fillMaxWidth(), { password = it }, submit)
Spacer(Modifier.height(12.dp))
LoginButton(ajax, Modifier.fillMaxWidth().height(56.dp), submit)
}
}
入力文字列などの情報はフォームに持たせています。こうすることで、ログイン処理を行うときに入力文字列を利用することができます。
3つの各要素では modifier
を引数として受け取っていました。そのように実装することで、呼び出し側で細かなスタイルの調節ができるようになります。
終わりに
メールアドレス入力欄からパスワード入力欄にフォーカスを移動させるとき、はじめは方法が思い浮かばずに悩んでいましたが、LocalFocusManager.current
を使うことでフォーカスを次に移す処理が簡単に実装できます。参考にしていただけると嬉しいです。