ask me! appのログイン画面の実装

#1 この記事の内容

ask me! appでのログイン画面の実装方法について記載します。画面レイアウトは下記のとおりです。

![quitta①+.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/681104/a12634d1-d61e-627d-f6a0-1a79eb294dd6.jpeg)




#2　ソースコード概要

ソースコードの概要は下記の通りです。

```dart:login.dart


  @override
  Widget build(BuildContext context) {
    return
      new GestureDetector(
      onTap:()
      {
        _focusNodePwd.unfocus();
      },
      child:

      new Scaffold(
      appBar: new AppBar(
      centerTitle: true,

        title: new Text('ask me! app',style: TextStyle(fontFamily: 'impact')),
        backgroundColor:Color.fromARGB(255,171 ,232 ,255 ),

      ),

      body:
      KeyboardActions(
      config:_buildConfig(context),
    child:
    
          _loading?
        bodyProgress:
        new Column(
            children: <Widget>[

              new Padding(
                padding:  EdgeInsets.fromLTRB(24.0*app_size.width/WIDTH,24.0*app_size.height/HEIGHT,24.0*app_size.width/WIDTH,24.0*app_size.height/HEIGHT),
              ),

              new Center(
                child:
                new Text(
                  "H E L L O",
                  style: new TextStyle(fontSize: 56.0*app_size.width*app_size.height/WIDTH/HEIGHT,
                      color: Color.fromARGB(255,171 ,232 ,255 ),
                      fontWeight: FontWeight.w300,
                      fontFamily: 'impact'),
                ),
              ),


              new Center(
                child:
                new Image.asset(
                  'icon/askme.png',
                  width: 230.0*app_size.width/WIDTH,
                  height: 230.0*app_size.width/WIDTH,
                ),
              ),


              new Padding(
                padding:  EdgeInsets.fromLTRB(20.0*app_size.width/WIDTH,10.0*app_size.height/HEIGHT,20.0*app_size.width/WIDTH,10.0*app_size.height/HEIGHT),
              ),


              new Container(
                  width: 300.0*app_size.width/WIDTH,
                  child:new EnsureVisibleWhenFocused(
                    focusNode: _focusNodePwd,
                    child: new TextFormField(
                      controller: passwdcontroller,
                      decoration: const InputDecoration(
                        border: const OutlineInputBorder(),
                        hintText: 'PASSWORD',
                        labelText: 'PASSWORD',
                        hintStyle: TextStyle(fontSize: 20.0,
                            color: const Color(0xFF000000),
                            fontWeight: FontWeight.w200,
                            fontFamily: 'impact'),
                        labelStyle:  TextStyle(fontSize: 20.0,
                            color: const Color(0xFF000000),
                            fontWeight: FontWeight.w200,
                            fontFamily: 'impact'),

                      ),
                      style: new TextStyle(fontSize: 20.0,
                          color: const Color(0xFF000000),
                          fontWeight: FontWeight.w200,
                          fontFamily: 'Roboto'),
                      focusNode: _focusNodePwd,
                      keyboardType: TextInputType.number,
                    ),
                  ),
              ),

              new Padding(
                padding:  EdgeInsets.fromLTRB(20.0*app_size.width/WIDTH,20.0*app_size.height/HEIGHT,20.0*app_size.width/WIDTH,20.0*app_size.height/HEIGHT),
              ),


              new Row(
                  children: <Widget>[

                    new Padding(
                      padding:  EdgeInsets.fromLTRB(app_size.width*0.1,40.0*app_size.height/HEIGHT,0.1*app_size.width,40.0*app_size.height/HEIGHT),
                    ),


                  new Container(

                    width:app_size.width*3/5,
                    child:
                    FlatButton(
                      onPressed: () {

                        buttonPressed();
                      },
                      color: Color.fromARGB(255,171 ,232 ,255 ),
                      child: Text(
                        "    OK    ",
                        style: new TextStyle(fontSize: 50.0,
                            fontWeight: FontWeight.w200,
                            fontFamily: 'impact'
                            ,color: Colors.white
                        ),
                      ),
                      padding: EdgeInsets.symmetric(vertical: 0*app_size.height, horizontal: 0.05*app_size.width),
                     shape:  StadiumBorder()
                    ),
                  ),
       
                    new Padding(
                      padding:  EdgeInsets.fromLTRB(app_size.width*0.1,40.0*app_size.height/HEIGHT,0.1*app_size.width,40.0*app_size.height/HEIGHT),
                    ),

                  ]
              ),
            ]

        ),
      ),

        bottomNavigationBar: new BottomNavigationBar(
          items: [

            new BottomNavigationBarItem(
              icon: const Icon(Icons.arrow_back),
              title: new Text('back',style: TextStyle(fontFamily: 'impact'),),
            ),


          ],
          onTap:(int index){
            Navigator.of(context).pop();
          },
        ),
      ),
      );
  }

```

工夫点について個別に説明します。

#3 端末のサイズ取得

端末の種類によってレイアウトが変わってしまうのを防ぐために、Container等のwidthには予め取得されたデバイスのサイズを利用します。

サイズ取得に失敗する場合もあるので、その時は再度get_size()を呼び出すようにしています。

ソースコードは下記の通りです。

```dart:login.dart

  void get_size(){
    app_size=MediaQuery.of(context).size;
    setState(() {
      width = app_size.width;
      height = app_size.height;
    });

    if(width==0 || height==0) get_size();
  }

  @override
  void initState()  {
    super.initState();
    get_size();
  }

```

参考サイト：https://qiita.com/najeira/items/c98c5fec9c71104f8263


#4 パスワード入力欄 のフォーカス外し

パスワードを入力するために、TextFormFieldをタップするとキーパッドが出ますが、
TextFormField外の箇所をタップするとキーパッドを閉じるようにしました。

実装方法としては、下記の通りです。

```dart:login.dart

      new GestureDetector(
      onTap:()
      {
        _focusNodePwd.unfocus();
      },

```

つまりOnTapイベントでパスワード入力欄に紐づけられたFocusNodeをUnFocusします。

#5 TextFormFieldのヘルパーウィジェット

キーバッドが表示されたときに、TextFormFieldが隠れてしまう場合があります。
それを防ぐために下記サイトのヘルパーウィジェットを利用しました。

URL:https://www.didierboelens.com/2018/04/hint-4-ensure-a-textfield-or-textformfield-is-visible-in-the-viewport-when-has-the-focus/

#6 キーパッドのDoneボタン

キーパッドでの入力完了後にはDoneボタンを押すことでキーパッドを閉じるようにしました。

Doneボタンの表示には下記のライブラリを使用しました。

Keyboard Actions:https://pub.dev/documentation/keyboard_actions/latest/


#7 OKボタン押下時の動作

OKボタン押下時には、入力されたパスワードと予め設定された正解パスワードが合致するかどうか判定しますが、
その際の待ち時間は下記画面のようにCircularProgressIndicatorを使用します。

![quitta_②.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/681104/10b4b671-cf33-9e23-9c5f-06fdb38e8401.jpeg)

ソースコードは下記のとおりです。

```dart:login.dart

  var bodyProgress = new Container(
    child: new Stack(
      children: <Widget>[
        //body,
        new Container(
          alignment: AlignmentDirectional.center,
          decoration: new BoxDecoration(
            color: Colors.white70,
          ),
          child: new Container(
            decoration: new BoxDecoration(
                color: Colors.blue[200],
                borderRadius: new BorderRadius.circular(10.0)
            ),
            width: 300.0,
            height: 200.0,
            alignment: AlignmentDirectional.center,
            child: new Column(
              crossAxisAlignment: CrossAxisAlignment.center,
              mainAxisAlignment: MainAxisAlignment.center,
              children: <Widget>[
                new Center(
                  child: new SizedBox(
                    height: 50.0,
                    width: 50.0,
                    child: new CircularProgressIndicator(
                      value: null,
                      strokeWidth: 7.0,
                    ),
                  ),
                ),
                new Container(
                  margin: const EdgeInsets.only(top: 25.0),
                  child: new Center(
                    child: new Text(
                      "please wait...",
                      style: new TextStyle(
                          color: Colors.white
                      ),
                    ),
                  ),
                ),
              ],
            ),
          ),
        ),
      ],
    ),
  );



```