入力値の検証とフォーカス制御
入力値の長さが1文字以下であることを確認し、該当する位置のcodeArrayに値を格納します。これにより各入力フィールドが単一文字のみを受け付けるようにします。
次の入力フィールドが存在するか(現在のindex + 1がcodeArrayの長さより小さいか)を確認します。存在する場合、自動的に次の入力フィールドにフォーカスを移動させ、ユーザーが連続して入力できるようにします。
次の入力フィールドが存在しない場合、inputCompleteCallback関数を呼び出し、入力値を親コンポーネントや呼び出し元に渡します。
キー属性の設定
各TextInputコンポーネントにkey属性を追加し、focusController.requestFocusが正しくトリガーされるようにします。ここではindexを使用して一意のキーを生成します。
発生した問題と解決策
1. 初期フォーカスの欠如
初期表示時にどの入力フィールドにもフォーカスが設定されません。以下のコードをTextInputに追加することで解決します:
.defaultFocus(index == 0)
2. 削除操作時のonChange非トリガー
現在のバージョンでは削除操作がonChangeメソッドをトリガーしません。onKeyEventを使用した代替案も期待通り動作しませんでした。
3. ソフトキーボードの表示異常
requestFocusを使用して次の入力フィールドにフォーカスを移動すると、ソフトキーボードが閉じてしまいます。現在のTextInputコンポーネントでは完全な解決が難しいため、別のアプローチを採用します。
代替アプローチ:Text() + TextInput()の組み合わせ
複数の入力フィールドで問題が発生するため、単一のTextInputと複数のTextコンポーネントを組み合わせた解決策を提案します。
@Component
struct VerificationCodeInput {
@State codeArray: string[] = new Array(5).fill('')
inputCompleteCallback: (string) => void
private inputId = "verification_input"
@State showCursor: boolean = true
build() {
Stack() {
Row({ space: vp(10) }) {
ForEach(this.codeArray, (char: string, idx: number) => {
Text(char)
.backgroundColor($r('app.color.white_80'))
.fontSize(fp(25))
.textAlign(TextAlign.Center)
.borderRadius(vp(15))
})
}
TextInput()
.maxLength(this.codeArray.length)
.key(this.inputId)
.onChange((inputValue) => {
const chars = inputValue.split('')
this.codeArray.forEach((_, pos) => {
this.codeArray[pos] = chars[pos] || ''
})
if (chars.length >= this.codeArray.length) {
this.inputCompleteCallback(inputValue)
}
this.showCursor = (chars.length === 0)
})
.fontColor(Color.Transparent)
.backgroundColor(Color.Transparent)
.caretColor(this.showCursor ? Color.Black : Color.Transparent)
}
.height(vp(80))
}
}
実装のポイント
- TextInputをレイアウト全体に広げ、最前面に配置します
- 文字色と背景色を透明に設定して入力フィールドを隠します
- 対応する数のTextコンポーネントを表示用に配置します
- onChange内で入力文字列を分割し、各位置の配列に格納します
コンポーネントの使用方法
VerificationCodeInput({
inputCompleteCallback: (code) => {
// 検証コードの処理を実装
}
})
カスタマイズの拡張
入力フィールドの幅、高さ、角丸、色、入力タイプ、数量などのパラメータをオブジェクトにまとめ、@Stateで修飾することで、柔軟なカスタマイズが可能になります。