本記事はFlutterを使ったWordleクローンアプリ開発日記のpart5になります
以前の記事:
【アプリ開発日記】アプリを開発するにあたっての流れとコツ【part1】
【アプリ開発日記】Widgetを切り出して作成する【part2】
【アプリ開発日記】ブロックのWidgetを作成する【part3】
【アプリ開発日記】キーボードのイベントを通知する【part4】
これまでは、UIを中心に実装を進めてきました。Wordleクローンの部分に関してはUIが最低限実装できたので、次は文字を扱う基本機能の部分を実装します。
カスタムの例外を作成する
Widget側は文字の入力状態を何も気にしなくて良いように進めます。その際、Enterキーを押された際にエラーとなるパターンとして以下が考えられます。
- 判定した結果不正解だった
- 文字数エラー(5文字以外の状態)
- 単語が存在しないエラー(辞書に載っていない)
Enterキーを押された際のAPIを作成する際、戻り値をbool型とすることで1番を扱うことが可能です(正解の場合はtrueを返し、不正解の場合はfalseを返す)。ただ、2番3番に関してはユーザにフィードバックが別途必要となるため、bool型の引数だけでは処理することができません。もちろん、戻り値をint型にし、それぞれのエラーであることがわかるようにしても良いですが、例外として扱うことで「判定が正しく行えていない」という意味を持たせています。
/// 文字の長さ判定エラー用Exception class WordLengthException implements Exception { } /// 単語が存在しない場合用のException class WordNotExistException implements Exception { }
文字管理を行う
前述したとおり、Widget側では文字の入力状態を一切管理しなくて良いようにします。キーが入力された時用、DELキーが押された時用、Enterキーが押された時用の3つを用意します。長さチェックや単語が存在するかどうかのAPIはprivateとすることでWidget側からは見えないようにしています。
class WordController { static const kWordCount = 6; //チャレンジ回数 static const kWordLength = 5; //単語の長さ int _currentCount = 0; final List<String> _wordList = ['', '', '', '', '', '']; // finalにしているが、間接的にデータの中身は書き換わる String answer = 'EARLY'; // FIXME WordController(); void initAnswer() { // TODO 回答をランダムに設定する } /// 1文字を追加する void appendLetter(String letter) { if (_checkWordLength()) { //5文字になっている場合は追加しない return; } if (letter.length == 1) { _wordList[_currentCount] += letter; } else { // FIXME throw exception ? } } /// 末尾の文字を削除する void removeLetter() { if (_wordList[_currentCount].isNotEmpty) { _wordList[_currentCount] = _wordList[_currentCount].substring( 0, _wordList[_currentCount].length - 1); } } bool enterLetter() { // 文字の長さを確認する if (!_checkWordLength()) { throw WordLengthException(); } // 単語が存在するかどうか確認する if (!_isWordExist()) { throw WordNotExistException(); } // 文字に問題がなければ答えと判定を行う if (answer == _wordList[_currentCount]) { return true; } else { // 誤りの場合はカウンターをインクリメントする _currentCount++; return false; } } // 5文字かどうか判定する bool _checkWordLength() { return _wordList[_currentCount].length == 5; } bool _isWordExist() { // TODO 存在する英単語かどうか確認する return true; } }
最後にmain.dart内のキーボードからのイベントを紐づけることで入力管理ができました。
SoftwareKeyBoard( onTapEnterKey: () { debugPrint('onTapEnterKey'); try { if (controller.enterLetter()) { // 正解 debugPrint('正解'); const snackBar = SnackBar(content: Text('正解です')); ScaffoldMessenger.of(context).showSnackBar(snackBar); } else { // 不正解 debugPrint('不正解'); // TODO Widgetの更新 } } on WordNotExistException catch(e) { debugPrint('WordNotExistException'); const snackBar = SnackBar(content: Text('存在しない単語です')); ScaffoldMessenger.of(context).showSnackBar(snackBar); } on WordLengthException catch(e) { debugPrint('WordLengthException'); const snackBar = SnackBar(content: Text('5文字入力してください')); ScaffoldMessenger.of(context).showSnackBar(snackBar); } catch(e) { // do nothing debugPrint('catch'); } }, onTapKey: (String char) { debugPrint('onTap : $char'); controller.appendLetter(char); }, onTapDeleteKey: () { debugPrint('onTapDeleteKey'); controller.removeLetter(); }, ),
あとはUI更新、ゲーム開始・終了の判定ぐらいでしょうか(7回目の単語が入力できるようになっちゃってますね)。
コメントを残す