前段时间Flutter的文章超多,再加上以前的同事也在开始使用Flutter开发项目了,为了积累吹NB的资料,不得不了解一下,然后写个练习练练手。总体感觉还不错,虽然这类文章也很多。但毕竟是别人学习后的总结,跟自己敲一遍的理解是没法比的。看着永远比做着简单。(就像这段文字的缩进,之前我一直都用的全角空格。直到后来失效我才发现原来两个 就能实现这样的效果,当然还有别的方式)。
废话不多说,撸个下面的界面就完事。
先来分析一个这个界面。真没啥好分析的,最简单的就是一个线性布局,然后往里扔子控件就行了。当然Flutter中也用类似的控件。这里我选用ListView,为啥不用Column。因为在这个布局中如果用Column包裹TextField,当弹出键盘时会出现遮挡,而ListView是可滚动的不会出现遮挡,这里我懒得深入研究,所以投机取巧了。所以这界面就可以这么弄了,使用ListView作为子控件的容器,让后一次往里放图片,输入框和按钮就能完成这个界面。
为了体现出练习的作用,当然这是借口。因为我没找到如何修改TextField边框高度的方法,所以在TextField外又包了一层。功能很简单就是当TextField焦点发生改变的时候,改变一下边框的颜色。下面直接甩出代码:
///输入控件
class MyInputView extends StatefulWidget {
final TextEditingController controller;
final bool obscureText;
final String hintText;
final StatelessWidget icon;
MyInputView(this.hintText, this.icon,
this.controller, {this.obscureText = false});
@override
State<StatefulWidget> createState() {
return MyInputViewState(
hintText, icon, obscureText, controller);
}
}
///输入控件的状态控制器
class MyInputViewState extends State<MyInputView> {
final controller;
final obscureText;
final hintText;
final icon;
final focusNode = FocusNode();
MyInputViewState(this.hintText, this.icon,
this.obscureText, this.controller);
///边框的默认颜色
var borderColor = Colors.grey;
var inputBorder;
@override
Widget build(BuildContext context) {
///监听输入框的焦点变化
focusNode.addListener(() {
setState(() {
borderColor = focusNode.hasFocus ? Theme
.of(context)
.primaryColor : Colors.grey;
});
});
///设置边框
inputBorder = BoxDecoration(
border: Border.all(
color: borderColor,
width: 1.5,
),
borderRadius: BorderRadius.all(
Radius.circular(10.0)
)
);
return Container(
child: createInputView(
hintText, icon, controller, obscureText),
);
}
///创建输入框
createInputView(hint, icon, controller, obscureText) {
return Container(
padding: EdgeInsets.only(left: 10.0),
child: TextField(
focusNode: focusNode,
controller: controller,
decoration: InputDecoration(
icon: icon,
hintText: hint,
border: InputBorder.none
),
obscureText: obscureText,
),
decoration: inputBorder
);
}
}
为了证明这段代码还有点作用,我们来对比一下。先把控件放到界面中,然后运行看一下效果。
import 'package:flutter/material.dart';
void main() =>
runApp(MaterialApp(
home: MyApp(),
));
class MyApp extends StatelessWidget {
final titleStyle = TextStyle(fontSize: 20.0);
final titleColor = Colors.blue;
@override
Widget build(BuildContext context) =>
Scaffold(
appBar: AppBar(
title: Text('对比'),
centerTitle: true
),
body: Padding(
padding: EdgeInsets.all(10.0), //设置边距
child: Column(
mainAxisAlignment: MainAxisAlignment.center, //内容居中
children: <Widget>[
createTitle('自定义的输入框'),
MyInputView(
'请输入姓名',
Icon(Icons.person),
TextEditingController()
),
SizedBox(height: 10.0),
createTitle('默认的输入框'),
TextField(
decoration: InputDecoration(
hintText: '请输入姓名',
prefixIcon: Icon(Icons.person),
border: OutlineInputBorder()
),
)
]
),
)
);
createTitle(String title) =>
Title(
child: Text(title, style: titleStyle),
color: titleColor);
}
接下来就好整了,向布局中依次添加logo、输入框和按钮。然后稍微优化一下布局,比如让子控件之间有点距离啥的。这样一个简单的登录界面就完成了。代码很简单,就是有点迷之缩进看着有点恶心。
import 'package:flutter/material.dart';
import 'package:fluttertoast/fluttertoast.dart';
void main() =>
runApp(MaterialApp(
home: MyApp(),
));
///登录界面
class MyApp extends StatelessWidget {
final userNameController = TextEditingController();
final passwordController = TextEditingController();
@override
Widget build(BuildContext context) {
const paddingValue = 30.0;
var padding = Padding(
padding: EdgeInsets.only(left: paddingValue, right: paddingValue),
child: createColumn(context));
return Scaffold(
appBar: AppBar(
title: Text('登录页'),
centerTitle: true,
),
body: padding
);
}
///设置界面中的视图效果
createColumn(context) {
return ListView(
children: <Widget>[
createColumnDriver(20.0),
///1、图片Logo
Image.asset(
'images/fish.png',
color: Theme
.of(context)
.primaryColor,
height: 160.0,
),
createColumnDriver(20.0),
///2、用户输入框
MyInputView(
'请输入姓名', ImageIcon(AssetImage('images/userName_icon.png')),
userNameController
),
createColumnDriver(20.0),
///3、密码输入框
MyInputView(
'请输入密码', ImageIcon(AssetImage('images/password_icon.png')),
passwordController,
obscureText: true,
),
createColumnDriver(30.0),
///4、登录按钮
createLoginBtn(context)
],
);
}
///垂直间隔
createColumnDriver(double height) => SizedBox(height: height);
///登录按钮
createLoginBtn(context) {
var loginBtn = RaisedButton(
child: Padding(
padding: EdgeInsets.all(10.0),
child: Text('登录',
style: TextStyle(
fontSize: 15.0,
fontWeight: FontWeight.bold
),
),
),
onPressed: () =>
Fluttertoast.showToast(
msg: '账号:${userNameController.text}\n密码:${passwordController.text}'),
textColor: Colors.white,
highlightColor: Theme
.of(context)
.primaryColorDark,
color: Theme
.of(context)
.primaryColor,
shape: StadiumBorder(),
);
return Row(children: <Widget>[
Expanded(
child: loginBtn,
)
]);
}
}
在输入框中输入内容,然后点击按钮。弹出一个Toast显示我们输入的内容。
Fluttertoast这个是第三方库,多了不说反正很好用。