OTP 入力(コード入力) OTP / PIN Code Input
4〜6桁のコードを1文字ずつの箱に入れる入力欄。打つと次の箱へ進み、全部埋まると自動で確認が始まる。
本物の Flutter ウィジェットが動きます(初回は数秒かかります)
どんなもの?
SMS やメールで届く確認コードを入れてもらう形です。
箱ごとに TextField を並べると、フォーカスの移動や消すときの戻りが複雑になります。
見えない TextField を1つだけ置いて、打った文字を箱に振り分けて描くと、貼り付けや消去も普通に動きます。
Opacity で隠すときは alwaysIncludeSemantics: true を付けます。付けないと、読み上げ機能が有効な Web では入力欄ごと消えて文字を受け取れませんでした。
keyboardType: TextInputType.number と maxLength で数字だけ・桁数までに絞り、
autofillHints: [AutofillHints.oneTimeCode] を付けると、iOS では届いた SMS のコードを候補に出せます。
次に打つ箱の枠を目立たせ、埋まったら onChanged で桁数を見て確認処理を始めます。
パッケージなら pinput や pin_code_fields で、見た目の種類やアニメーションを含めて作れます。
こんなときに
- SMS・メールで届いた確認コード、アプリのロック解除用の暗証番号
避けたい場面
- 桁数が決まっていない入力(普通のテキスト入力にする)
最小コード
Stack(children: [
// 見えない入力欄が1つだけ(貼り付け・消去も普通に効く)
Opacity(
opacity: 0,
alwaysIncludeSemantics: true, // 読み上げ有効の Web で入力欄が消えないように
child: TextField(
controller: code,
focusNode: focus,
maxLength: 6,
keyboardType: TextInputType.number,
autofillHints: const [AutofillHints.oneTimeCode],
onChanged: (v) { if (v.length == 6) verify(v); },
),
),
// 打った文字を6つの箱に描く
GestureDetector(
onTap: focus.requestFocus,
child: Row(children: [
for (var i = 0; i < 6; i++)
_Box(
char: i < code.text.length ? code.text[i] : '',
active: i == code.text.length,
),
]),
),
])使うウィジェット
TextField(maxLength)StackAnimatedContainer
パッケージ: pinput ↗pin_code_fields ↗