先週初めてFirebaseを使ってみたので備忘録的に残しておきます。
フォームでEmailとパスワードを入力し、Firebaseとの接続を確認できたところをゴールとします。
参考になると思う方
- Flutterの環境構築ができてる
とりあえずHello World
import 'package:flutter/material.dart';
import 'login_page.dart';
void main() {
runApp(new MyApp());
}
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return new MaterialApp(
title: 'Flutter auth',
theme: new ThemeData(
primarySwatch: Colors.blue,
),
home: new LoginPage(),
);
}
}
login_page.dart
ファイルを作成し、こちらにAuthの具体的なコードを書いていきます。
import 'package:flutter/material.dart';
class LoginPage extends StatefulWidget {
@override
State<StatefulWidget> createState() => new _LoginPageState();
}
class _LoginPageState extends State<LoginPage> {
@override
Widget build(BuildContext context) {
return new Scaffold(
appBar: new AppBar(
title: new Text('Flutter auth'),
),
body: new Container(
child: new Text('Hello World')
),
);
}
}
home: new LoginPage()
homeにlogin_page.dartファイルのLoginPageクラスを返してるということですね。
とりあえずこんな感じ。
フォームの作成
bodyのContainerに変更を加えていきます。
class _LoginPageState extends State<LoginPage> {
@override
Widget build(BuildContext context) {
return new Scaffold(
appBar: new AppBar(
title: new Text('Flutter auth'),
),
body: new Container(
//追加
child: new Form(
child: new Column(
children: <Widget>[
new TextFormField(
decoration: new InputDecoration(labelText: 'Email'),
),
new TextFormField(
decoration: new InputDecoration(labelText: 'Password'),
),
],
)
)
),
);
}
ここでchildとchildrenの違いについて説明しておきます。
child takes a single widget
child: Text('foo')
children takes a list of widgets
children: [Text('foo'), Text('bar')]
childは一つのWidgetのみをとり、childrenはWidgetをリストとしていくつもとることができると。
今回の例でもForm Widgetの中のchildにColumn Widgetを入れ、そのプロパティにchildrenを使用することでTextFormField
として二つのFormをリストとして表示しています。
ボタンの作成
class _LoginPageState extends State<LoginPage> {
//追加
void validateAndSave() {
}
@override
Widget build(BuildContext context) {
return new Scaffold(
appBar: new AppBar(
title: new Text('Flutter auth'),
),
body: new Container(
//追加
padding: EdgeInsets.all(16.0),
child: new Form(
child: new Column(
//追加
crossAxisAlignment: CrossAxisAlignment.stretch,
children: <Widget>[
new TextFormField(
decoration: new InputDecoration(labelText: 'Email'),
),
new TextFormField(
decoration: new InputDecoration(labelText: 'Password'),
),
//追加
new RaisedButton(
child: new Text('Login', style: new TextStyle(fontSize: 20.0)),
onPressed: validateAndSave,
),
],
)
)
),
);
}
}
とりあえずボタンを作ります。
new RaisedButton(
child: new Text('Login', style: new TextStyle(fontSize: 20.0)),
onPressed: validateAndSave,
onPressed
でボタンを押した時の処理を実行します。
処理を行うvalidateAndSave
関数はあとで記述します。
あとはイケてないところを少し修正します。
padding: EdgeInsets.all(16.0),
これでスペースを整え、
crossAxisAlignment: CrossAxisAlignment.stretch,
こちらでボタンを画面いっぱいに引き延ばします。
| 種別 | 内容 |
|:--|:--|
| baseline | テキストのベースラインを揃えるように配置される |
| center | 中央寄せになる |
| start | Columnなら左寄せ(厳密にはTextDirectionによって開始位置が決まる) |
| Rowなら上寄せになる(厳密にはVerticalDirectionによって開始位置が決まる) |
| end | Columnなら右寄せ(厳密にはTextDirectionによって開始位置が決まる) |
| Rowなら上寄せになる(厳密にはVerticalDirectionによって開始位置が決まる) |
| streach | 子要素の幅また高さを埋めるように配置する |
参考:https://qiita.com/kaleidot725/items/35f6940e594bdf073eb8#crossaxisalignment
crossAxisAlignmentについてはこちらに詳しく書いてあるので参考にしてみてください。
UIはいい感じになりましたね。
loginフォームにvalidationをかけ、saveする
body: new Container(
padding: EdgeInsets.all(16.0),
child: new Form(
//追加
key: formKey,
child: new Column(
crossAxisAlignment: CrossAxisAlignment.stretch,
children: <Widget>[
new TextFormField(
decoration: new InputDecoration(labelText: 'Email'),
//追加
validator: (value) => value.isEmpty ? 'Email can\'t be empty' : null,
onSaved: (value) => _email = value,
),
new TextFormField(
decoration: new InputDecoration(labelText: 'Password'),
//追加
obscureText: true,
validator: (value) => value.isEmpty ? 'Password can\'t be empty' : null,
onSaved: (value) => _password = value,
),
new RaisedButton(
child: new Text('Login', style: new TextStyle(fontSize: 20.0)),
onPressed: validateAndSave,
),
],
)
)
),
keyについてなのですが、少し難しく、まだ浅い理解に留まっています
Controls how one widget replaces another widget in the tree.
In addition, using a GlobalKey as the widget's key allows the element to be moved around the tree (changing parent) without losing state. When a new widget is found (its key and type do not match a previous widget in the same location), but there was a widget with that same global key elsewhere in the tree in the previous frame, then that widget's element is moved to the new location.
Flutter公式: https://api.flutter.dev/flutter/widgets/Widget/key.html
ツリー内にあるWidgetを他のWidgetに入れ替えるのをコントロールすると。
さらに、GlobalKeyをWidgetのkeyとして使用すると状態を失うことなく、Elementをツリー内で移動できると(親を変える)。
ああ〜なるほどね...(わからん)
一応良さげな記事を見つけたので置いておきます。これはFlutterというフレームワークそのものの理解が必要そうです。
動画をみてもわからなかった...
Keys! What are they good for?: https://medium.com/flutter/keys-what-are-they-good-for-13cb51742e7d
validator: (value) => value.isEmpty ? 'Email can\'t be empty' : null,
onSaved: (value) => _email = value,
formが空だった場合にはnullとEmail can't be empty
というテキストを返し、入力された場合はセーブします。
パスワードも同じように実装しますが、打った文字が隠れるように下記のコードを記述します。
obscureText: true,
次にボタンを押した時の処理を加えていきます。
class _LoginPageState extends State<LoginPage> {
final formKey = new GlobalKey<FormState>();
String _email;
String _password;
void validateAndSave() {
final form = formKey.currentState;
if(form.validate()) {
form.save();
print('Form is valid. Email: $_email, password: $_password');
} else {
print('Form is Invalid. Email: $_email, password: $_password');
}
}
上からformKeyと_email、_passwordを定義します。
定数の前に_(アンダースコア)がついていることに気づくと思うのですが、これはdartの言語使用で、そのライブラリ内だけ参照できるように制限をかけるものらしいです。
空欄のままボタンを押すと上の写真のようにDEBUG CONSOLEではflutter: Form is Invalid. Email: null, password: null
と表示されたでしょうか?
そのあとEmailとPasswordに「test」と入力してボタンを押すとflutter: Form is valid. Email: test, password: test
Form is validしたことを確認できると思います
あとはFirebaseと接続してデータベースに反映させるだけです!!
Firebaseのライブラリを追加
このサイトに飛んで最新バージョンのfirebase_auth
をインストールします。
dart package: https://pub.dev/packages/firebase_auth#-installing-tab-
dependencies:
flutter:
sdk: flutter
firebase_auth: ^0.15.4
# The following adds the Cupertino Icons font to your application.
# Use with the CupertinoIcons class for iOS style icons.
cupertino_icons: ^0.1.2
セーブすると自動的にflutter pub get
が走ると思います。
import 'package:firebase_auth/firebase_auth.dart';
ここからはFirebaseの設定に入るのですが、長くなってきたので二つの記事に分けます。
ではこちらの記事で
【Flutter】FirebaseのAuthでメアド&パスワード認証を実装する(後半)
https://qiita.com/iketeruhiyoko/items/7d0718bc6210ed545913
参考
Flutter & Firebase Auth 02 - Create, validate and save a login form + Firebase iOS auth integration
https://www.youtube.com/watch?v=BNOUtPSN-kA