#1 この記事の内容
ask me! appでのログイン画面の実装方法について記載します。画面レイアウトは下記のとおりです。
#2 ソースコード概要
ソースコードの概要は下記の通りです。
@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()を呼び出すようにしています。
ソースコードは下記の通りです。
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外の箇所をタップするとキーパッドを閉じるようにしました。
実装方法としては、下記の通りです。
new GestureDetector(
onTap:()
{
_focusNodePwd.unfocus();
},
つまりOnTapイベントでパスワード入力欄に紐づけられたFocusNodeをUnFocusします。
#5 TextFormFieldのヘルパーウィジェット
キーバッドが表示されたときに、TextFormFieldが隠れてしまう場合があります。
それを防ぐために下記サイトのヘルパーウィジェットを利用しました。
#6 キーパッドのDoneボタン
キーパッドでの入力完了後にはDoneボタンを押すことでキーパッドを閉じるようにしました。
Doneボタンの表示には下記のライブラリを使用しました。
Keyboard Actions:https://pub.dev/documentation/keyboard_actions/latest/
#7 OKボタン押下時の動作
OKボタン押下時には、入力されたパスワードと予め設定された正解パスワードが合致するかどうか判定しますが、
その際の待ち時間は下記画面のようにCircularProgressIndicatorを使用します。
ソースコードは下記のとおりです。
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
),
),
),
),
],
),
),
),
],
),
);