【新規登録画面】名前・所属・メール・パスワードを入力する画面を作る
このページでやること
このページでは、新規登録画面を作ります。
新規登録画面とは、まだアカウントを持っていない人が、名前・所属・メールアドレス・パスワードを入力して、アプリを使い始めるための画面です。
今回作る画面は、次のようなイメージです。
新規登録
プロフィール作成
名前
所属
メールアドレス
パスワード
[新規登録]
このページでは、まず画面を作るところまで進めます。
Firebase Authenticationにユーザーを作る処理や、Firestoreにプロフィールを保存する処理は、次のページで詳しく見ていきます。
今日のゴール
RegisterPage を作って、ログイン画面の「新規登録はこちら」から移動できるようにします。
ログイン画面
↓
新規登録はこちら
↓
新規登録画面
このページでは、次の4つの入力欄を作ります。
| 入力欄 | 一言説明 |
|---|---|
| 名前 | アプリ内で表示する名前 |
| 所属 | 学校名、部署名、チーム名など |
| メールアドレス | ログインに使うメール |
| パスワード | ログインに使う秘密の文字 |
このページで出てくる単語
| 単語 | 一言説明 |
|---|---|
RegisterPage | 新規登録画面を作るWidget |
StatefulWidget | 画面の中で変わる値を持てるWidget |
TextEditingController | 入力欄の文字を管理する道具 |
AppTextField | この教材で作った共通入力欄 |
Scaffold | Flutter画面の基本の土台 |
AppBar | 画面上部のバー |
SingleChildScrollView | 画面が小さいときにスクロールできる部品 |
FilledButton | 塗りつぶし型のボタン |
dispose | 使い終わった道具を片付ける処理 |
Widget とは、Flutterの画面部品のことです。
npmや環境変数はこのページで必要?
このページでは、npmは使いません。
npmとは、Node.jsのパッケージ管理ツールです。
環境変数も設定しません。
環境変数とは、パソコン全体で使う設定値のことです。
このページでやることは、これだけです。
main.dartを開く
↓
RegisterPageを書く
↓
保存する
↓
flutter runで確認する
Step 1:main.dartを開く
Flutterプロジェクトの中で、次のファイルを開きます。
lib/main.dart
VS Codeを使っている場合は、ターミナルで次を実行してもOKです。
code lib/main.dart
code が使えない場合は、VS Codeの左側から lib/main.dart を開いてください。
Step 2:古い仮のRegisterPageがある場合は消す
前のページで、仮の RegisterPage を作った人は、そのコードを消してください。
仮のコードは、だいたい次のような形です。
class RegisterPage extends StatelessWidget {
const RegisterPage({super.key});
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text('新規登録'),
),
body: const Center(
child: Text('新規登録画面は次のページで作ります'),
),
);
}
}
この仮コードを、今回作る本物の RegisterPage に差し替えます。
Step 3:RegisterPageを追加する
LoginPage の下あたりに、次のコードを追加します。
class RegisterPage extends StatefulWidget {
const RegisterPage({super.key});
@override
State<RegisterPage> createState() => _RegisterPageState();
}
RegisterPage は、新規登録画面です。
ここでは StatefulWidget を使います。
StatefulWidget とは、画面の中で変わる値を持てるWidgetです。
新規登録画面では、入力された名前、所属、メールアドレス、パスワード、読み込み中かどうか、エラー文などが変わります。
そのため、StatefulWidget を使います。
Step 4:入力欄用のControllerを作る
続けて、次のコードを追加します。
class _RegisterPageState extends State<RegisterPage> {
final displayNameController = TextEditingController();
final departmentController = TextEditingController();
final emailController = TextEditingController();
final passwordController = TextEditingController();
bool isLoading = false;
String? errorText;
TextEditingController は、入力欄に入力された文字を取り出すための道具です。
今回は4つの入力欄があるので、Controllerも4つ作ります。
| Controller | 入力する内容 |
|---|---|
displayNameController | 名前 |
departmentController | 所属 |
emailController | メールアドレス |
passwordController | パスワード |
isLoading は、新規登録中かどうかを表します。
errorText は、登録に失敗したときのエラー文を入れます。
null は、値がない状態のことです。
Step 5:disposeを書く
続けて、次のコードを追加します。
@override
void dispose() {
displayNameController.dispose();
departmentController.dispose();
emailController.dispose();
passwordController.dispose();
super.dispose();
}
dispose は、使い終わった道具を片付ける処理です。
TextEditingController は画面が消えるときに片付ける必要があります。
難しく考えなくて大丈夫です。
入力欄のControllerを作ったら、最後に dispose() で片付ける、と覚えてください。
Step 6:register()を仮で作る
このページでは、まだ本格的な登録処理は作りません。
まずは、ボタンを押したときに動く仮の register() を作ります。
続けて、次のコードを追加します。
Future<void> register() async {
setState(() {
errorText = null;
});
final displayName = displayNameController.text.trim();
final department = departmentController.text.trim();
final email = emailController.text.trim();
final password = passwordController.text;
if (displayName.isEmpty ||
department.isEmpty ||
email.isEmpty ||
password.isEmpty) {
setState(() {
errorText = 'すべての項目を入力してください。';
});
return;
}
setState(() {
errorText = '次のページでFirebase登録処理を追加します。';
});
}
trim() は、文字の前後にある余分な空白を消す処理です。
isEmpty は、文字が空かどうかを調べるものです。
return は、ここで処理を止めるという意味です。
この段階では、入力チェックだけ行います。
入力チェックとは、必要な項目が入っているか確認することです。
Step 7:画面部分を追加する
続けて、同じ _RegisterPageState の中に、次のコードを追加します。
@override
Widget build(BuildContext context) {
return Scaffold(
backgroundColor: AppColors.bg,
appBar: AppBar(
title: const Text('新規登録'),
),
body: SafeArea(
child: SingleChildScrollView(
padding: const EdgeInsets.all(20),
child: Center(
child: ConstrainedBox(
constraints: const BoxConstraints(maxWidth: 420),
child: AppCard(
child: Column(
crossAxisAlignment: CrossAxisAlignment.stretch,
children: [
const Text(
'プロフィール作成',
textAlign: TextAlign.center,
style: TextStyle(
color: AppColors.text,
fontSize: 24,
fontWeight: FontWeight.w900,
),
),
const SizedBox(height: 8),
const Text(
'チームで使う名前とログイン情報を入力します',
textAlign: TextAlign.center,
style: TextStyle(
color: AppColors.subText,
fontWeight: FontWeight.w600,
),
),
const SizedBox(height: 24),
AppTextField(
controller: displayNameController,
label: '名前',
),
const SizedBox(height: 12),
AppTextField(
controller: departmentController,
label: '所属',
),
const SizedBox(height: 12),
AppTextField(
controller: emailController,
label: 'メールアドレス',
keyboardType: TextInputType.emailAddress,
),
const SizedBox(height: 12),
AppTextField(
controller: passwordController,
label: 'パスワード',
obscureText: true,
),
if (errorText != null) ...[
const SizedBox(height: 12),
ErrorBox(message: errorText!),
],
const SizedBox(height: 20),
FilledButton(
onPressed: isLoading ? null : register,
child: Text(isLoading ? '登録中...' : '新規登録'),
),
],
),
),
),
),
),
),
);
}
}
これで、新規登録画面のUIができます。
Scaffold は、画面の基本の土台です。
AppBar は、画面上部のバーです。
SafeArea は、スマホのノッチやステータスバーに画面が重ならないようにする部品です。
SingleChildScrollView は、画面が小さいときにスクロールできるようにする部品です。
ConstrainedBox は、横幅の最大サイズを決める部品です。
ここまでの完成コード
このページで追加する RegisterPage は、次の形です。
class RegisterPage extends StatefulWidget {
const RegisterPage({super.key});
@override
State<RegisterPage> createState() => _RegisterPageState();
}
class _RegisterPageState extends State<RegisterPage> {
final displayNameController = TextEditingController();
final departmentController = TextEditingController();
final emailController = TextEditingController();
final passwordController = TextEditingController();
bool isLoading = false;
String? errorText;
@override
void dispose() {
displayNameController.dispose();
departmentController.dispose();
emailController.dispose();
passwordController.dispose();
super.dispose();
}
Future<void> register() async {
setState(() {
errorText = null;
});
final displayName = displayNameController.text.trim();
final department = departmentController.text.trim();
final email = emailController.text.trim();
final password = passwordController.text;
if (displayName.isEmpty ||
department.isEmpty ||
email.isEmpty ||
password.isEmpty) {
setState(() {
errorText = 'すべての項目を入力してください。';
});
return;
}
setState(() {
errorText = '次のページでFirebase登録処理を追加します。';
});
}
@override
Widget build(BuildContext context) {
return Scaffold(
backgroundColor: AppColors.bg,
appBar: AppBar(
title: const Text('新規登録'),
),
body: SafeArea(
child: SingleChildScrollView(
padding: const EdgeInsets.all(20),
child: Center(
child: ConstrainedBox(
constraints: const BoxConstraints(maxWidth: 420),
child: AppCard(
child: Column(
crossAxisAlignment: CrossAxisAlignment.stretch,
children: [
const Text(
'プロフィール作成',
textAlign: TextAlign.center,
style: TextStyle(
color: AppColors.text,
fontSize: 24,
fontWeight: FontWeight.w900,
),
),
const SizedBox(height: 8),
const Text(
'チームで使う名前とログイン情報を入力します',
textAlign: TextAlign.center,
style: TextStyle(
color: AppColors.subText,
fontWeight: FontWeight.w600,
),
),
const SizedBox(height: 24),
AppTextField(
controller: displayNameController,
label: '名前',
),
const SizedBox(height: 12),
AppTextField(
controller: departmentController,
label: '所属',
),
const SizedBox(height: 12),
AppTextField(
controller: emailController,
label: 'メールアドレス',
keyboardType: TextInputType.emailAddress,
),
const SizedBox(height: 12),
AppTextField(
controller: passwordController,
label: 'パスワード',
obscureText: true,
),
if (errorText != null) ...[
const SizedBox(height: 12),
ErrorBox(message: errorText!),
],
const SizedBox(height: 20),
FilledButton(
onPressed: isLoading ? null : register,
child: Text(isLoading ? '登録中...' : '新規登録'),
),
],
),
),
),
),
),
),
);
}
}
Step 8:ログイン画面から移動できるか確認する
LoginPage の中に、次のコードがあるか確認します。
TextButton(
onPressed: isLoading
? null
: () {
Navigator.of(context).push(
MaterialPageRoute(
builder: (_) => const RegisterPage(),
),
);
},
child: const Text('新規登録はこちら'),
),
Navigator は、画面を移動するための仕組みです。
push は、新しい画面を上に重ねて表示する命令です。
MaterialPageRoute は、Material Design風に画面移動するための部品です。
このコードがあると、ログイン画面から新規登録画面へ移動できます。
Step 9:保存する
main.dart を保存します。
Macの場合:
command + S
Windowsの場合:
Ctrl + S
Step 10:実行する
ターミナルで実行します。
flutter run
すでに起動している場合は、ターミナルで r を押します。
r
r はホットリロードです。
ホットリロードとは、アプリを起動したまま画面の変更を反映する機能です。
Step 11:画面を確認する
ログイン画面で、次を押します。
新規登録はこちら
次のような画面が表示されればOKです。
新規登録
プロフィール作成
名前
所属
メールアドレス
パスワード
[新規登録]
ここでは、まだ本当にユーザー登録できなくても大丈夫です。
このページのゴールは、新規登録画面のUIを作ることです。
Step 12:入力チェックを確認する
何も入力せずに「新規登録」ボタンを押してみます。
次のエラーが表示されればOKです。
すべての項目を入力してください。
次に、4つの入力欄をすべて入力してから「新規登録」を押します。
名前:山田太郎
所属:開発チーム
メールアドレス:test@example.com
パスワード:password123
次の表示が出ればOKです。
次のページでFirebase登録処理を追加します。
これは仮の表示です。
次のページで、実際にFirebase Authenticationへ登録する処理に変更します。
1か所だけ変更してみる
画面の説明文を変えてみます。
この部分を探してください。
'チームで使う名前とログイン情報を入力します',
次のように変えてみます。
'はじめて使う方は、ここから登録してください',
保存して、ホットリロードします。
r
画面の文字が変われば成功です。
確認できたら、好きな表現に戻してOKです。
よくあるエラーと直し方
| エラー | 原因 | 直し方 |
|---|---|---|
RegisterPage is already defined | 仮のRegisterPageが残っている | 古いRegisterPageを削除する |
AppTextField isn't defined | 共通UIがない | AppTextField を追加する |
AppCard isn't defined | 共通UIがない | AppCard を追加する |
ErrorBox isn't defined | 共通UIがない | ErrorBox を追加する |
setState isn't defined | State クラスの外に書いている | _RegisterPageState の中に書く |
Navigator でエラー | material.dart のimport漏れ | import 'package:flutter/material.dart'; を確認 |
| 画面が変わらない | 保存していない | command + S |
| ホットリロードで直らない | 画面構成が大きく変わった | アプリを再起動する |
RegisterPage is already defined** が出たとき**
次のようなエラーが出た場合です。
The name 'RegisterPage' is already defined.
これは、RegisterPage が2つあるという意味です。
前に作った仮の RegisterPage が残っている可能性があります。
main.dart の中で class RegisterPage を検索してください。
VS Codeなら、
command + F
で検索できます。
class RegisterPage が2つあれば、古い仮の方を削除します。
setState isn't defined** が出たとき**
setState は、State クラスの中で使えます。
今回なら、次の中に書く必要があります。
class _RegisterPageState extends State<RegisterPage> {
// ここに書く
}
RegisterPage クラスの外に register() を書くと、setState が使えません。
最短作業まとめ
読むのが大変な人は、ここだけ見てください。
1. lib/main.dartを開く
2. 古い仮のRegisterPageがあれば消す
3. 新しいRegisterPageを追加する
4. LoginPageの「新規登録はこちら」からRegisterPageへ移動できるか確認する
5. 保存する
6. flutter run
実行コマンドです。
flutter run
起動中なら、
r
チェックリスト
□ main.dartを開いた
□ 古い仮のRegisterPageを削除した
□ RegisterPageをStatefulWidgetで作った
□ 名前用Controllerを作った
□ 所属用Controllerを作った
□ メール用Controllerを作った
□ パスワード用Controllerを作った
□ disposeを書いた
□ register()を仮で作った
□ AppTextFieldを4つ置いた
□ 新規登録ボタンを作った
□ 入力チェックが動いた
□ 保存した
□ flutter runで確認した
ミニ確認問題
Q1. RegisterPageは何をする画面ですか?
回答
新しいユーザーが、名前・所属・メールアドレス・パスワードを入力して登録するための画面です。
Q2. なぜRegisterPageはStatefulWidgetで作りますか?
回答
入力内容、読み込み中かどうか、エラー文など、画面の中で変わる値があるからです。
Q3. TextEditingControllerは何のために使いますか?
回答
入力欄に入力された文字を取り出すために使います。
Q4. このページでnpmや環境変数は必要ですか?
回答
必要ありません。
このページでは、新規登録画面のUIを作るだけです。
このページのまとめ
- このページでは、新規登録画面のUIを作った。
- 入力欄は、名前・所属・メールアドレス・パスワードの4つ。
- 入力された文字は
TextEditingControllerで管理する。 RegisterPageは、変化する値があるのでStatefulWidgetで作る。dispose()でControllerを片付ける。- まずは仮の
register()で入力チェックだけ行う。 - ログイン画面の「新規登録はこちら」から移動できるようにする。
- このページではnpmや環境変数は不要。
次のページでやること
次のページでは、実際にFirebase Authenticationへユーザーを作成します。
createUserWithEmailAndPassword を使って、入力したメールアドレスとパスワードで新しいアカウントを作ります。
