LoginSignup
3
1

More than 1 year has passed since last update.

Jetpack Compose でログインフォームを作る

Posted at

はじめに

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 はキーボードの右下にあるボタンの形式を表します。keyboardOptionsimeAction = ImeAction.XXXkeyboardActionsonXXX は密接に関係しており、たとえば 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 を使うことでフォーカスを次に移す処理が簡単に実装できます。参考にしていただけると嬉しいです。

3
1
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
3
1