开始学习一门全新的语言确实很慢,需要了解很多控件,个人的做法是大家都记不住这么多,所以就要做一个件事,那就是写博客,把你看到的情况都列出来,这样你遇到需求的时候就去翻翻控件那一篇,copycopy就记住了,也没有那么不想学了,可以去试试~这篇是我总结的各种前期遇到比较多的控件样式设置写法,以后会更新下去,这样每次记不住回来看一眼,跟API一样~
1.Widget:多写几次你会发现越写越顺,其实不是很绕,一看上去有点小乱,后面由于google智能的换行,所以很好找~试试吧~
import 'package:flutter/material.dart';
void main() => runApp(new MyApp());
//Stateless widgets 是不可变的, 这意味着它们的属性不能改变 - 所有的值都是最终的.
//Stateful widgets 持有的状态可能在widget生命周期中发生变化. 实现一个 stateful widget 至少需要两个类:
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
// final wordPair = new WordPair.random();
return new MaterialApp(
title: 'Welcome to Flutter',
debugShowCheckedModeBanner: false,
home: new Scaffold(
appBar: new AppBar(
title: new Text('Welcome to Flutter'),
),
body: new Center(
child: new Text('Hello World'),
),
),
);
}
}
2.文本及样式:我总结了一些常用的后续会继续更新,直接拿去用,目前看应该够用~
import 'package:flutter/material.dart';
import 'package:flutter/rendering.dart';
void main() => runApp(new MyApp());
//void main() {
// runApp(new MaterialApp(
// home: new MyApp(),
// ));
//}
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
// TODO: implement build
return new MaterialApp(
title: 'Flutter Demo1',
debugShowCheckedModeBanner: false,
theme: new ThemeData(
primarySwatch: Colors.blue,
// fontFamily: 'fontdemo1'
),
home: new MyHomePage(title: '文本及样式'),
);
}
}
class MyHomePage extends StatefulWidget {
MyHomePage({Key key, this.title}) : super(key: key);
final String title;
@override
State<StatefulWidget> createState() {
// TODO: implement createState
return new _MyHomePageState();
}
}
class _MyHomePageState extends State<MyHomePage> {
final textStyleAssetFont1 = const TextStyle(
fontFamily: 'fontdemo1',
);
final textStyleAssetFont2 = const TextStyle(
fontFamily: 'fontdemo2',
);
final textStyleAssetFont3 = const TextStyle(
letterSpacing: 2.0,
);
final textStyleAssetFont4 = const TextStyle(
height: 2.0,
);
@override
Widget build(BuildContext context) {
// TODO: implement build
return new Scaffold(
appBar: new AppBar(
title: new Text(
widget.title,
style: textStyleAssetFont2,
),
),
body: new Center(
child: new Column(
// mainAxisAlignment: MainAxisAlignment.start,
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
new Text(
"1.hi yun~",
textAlign: TextAlign.start,
style: textStyleAssetFont3,
),
new Text(
"2.hi yun~" * 16,
maxLines: 1,
overflow: TextOverflow.ellipsis,
style: textStyleAssetFont4,
// style: Theme.of(context).textTheme.display1,
),
new Text(
"3.hi yun~",
textScaleFactor: 1.5,
style: textStyleAssetFont4,
),
new Text(
"4.hi yun~" * 16,
textAlign: TextAlign.start,
style: textStyleAssetFont4,
),
new Text(
"5.hi yun~",
style: TextStyle(
color: Colors.blue,
fontSize: 18.0,
height: 2.0,
fontFamily: "Courier",
background: new Paint()..color = Colors.yellow,
decoration: TextDecoration.underline,
decorationStyle: TextDecorationStyle.dashed),
),
new Text(
"红色+黑色删除线+25号",
style: new TextStyle(
color: const Color(0xffff0000),
decoration: TextDecoration.lineThrough,
decorationColor: const Color(0xff000000),
fontSize: 25.0,
),
),
new Text.rich(TextSpan(children: [
TextSpan(text: "6.Yun:"),
TextSpan(
text: "https://flutterchina.club",
style: TextStyle(
color: Colors.blue,
height: 2.0,
),
// recognizer: _tapRecognizer
),
])),
DefaultTextStyle(
style: TextStyle(
color: Colors.red,
fontSize: 20.0,
height: 2.0,
),
textAlign: TextAlign.start,
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
Text("7.hi yun1~"),
Text("7.hi yun2~"),
Text(
"7.hi yun3~",
style: TextStyle(
inherit: false,
color: Colors.grey,
height: 2.0,
),
),
Text(
"8.hi yun~",
style: textStyleAssetFont2,
),
],
),
),
],
),
),
);
}
}
需要注意的是路径要对:
name: p001_flutter_demo1
description: A new Flutter application.
# The following defines the version and build number for your application.
# A version number is three numbers separated by dots, like 1.2.43
# followed by an optional build number separated by a +.
# Both the version and the builder number may be overridden in flutter
# build by specifying --build-name and --build-number, respectively.
# Read more about versioning at semver.org.
version: 1.0.0+1
environment:
sdk: ">=2.0.0-dev.68.0 <3.0.0"
dependencies:
flutter:
sdk: flutter
# The following adds the Cupertino Icons font to your application.
# Use with the CupertinoIcons class for iOS style icons.
cupertino_icons: ^0.1.2
english_words: ^3.1.5
dev_dependencies:
flutter_test:
sdk: flutter
# For information on the generic Dart part of this file, see the
# following page: https://www.dartlang.org/tools/pub/pubspec
# The following section is specific to Flutter.
flutter:
# The following line ensures that the Material Icons font is
# included with your application, so that you can use the icons in
# the material Icons class.
uses-material-design: true
assets:
- assets/demo.txt
- assets/images/
# To add assets to your application, add an assets section, like this:
# assets:
# - images/a_dot_burr.jpeg
# - images/a_dot_ham.jpeg
# An image asset can refer to one or more resolution-specific "variants", see
# https://flutter.io/assets-and-images/#resolution-aware.
# For details regarding adding assets from package dependencies, see
# https://flutter.io/assets-and-images/#from-packages
# To add custom fonts to your application, add a fonts section here,
# in this "flutter" section. Each entry in this list should have a
# "family" key with the font family name, and a "fonts" key with a
# list giving the asset and other descriptors for the font. For
# example:
# fonts:
# - family: Schyler
# fonts:
# - asset: fonts/Schyler-Regular.ttf
# - asset: fonts/Schyler-Italic.ttf
# style: italic
# - family: Trajan Pro
# fonts:
# - asset: fonts/TrajanPro.ttf
# - asset: fonts/TrajanPro_Bold.ttf
# weight: 700
#
fonts:
- family: fontdemo1
fonts:
- asset: assets/fonts/NotoSerifTC-Bold.otf
style: italic
- family: fontdemo2
fonts:
- asset: assets/fonts/ZCOOLKuaiLe-Regular.ttf
weight: 500
- family: iconfont
fonts:
- asset: assets/fonts/iconfont.ttf
weight: 700
# For details regarding fonts from package dependencies,
# see https://flutter.io/custom-fonts/#from-packages
3.图片及icon:这里多了一个iconfont.cn的操作,大家可以了解一下
import 'package:flutter/material.dart';
void main() => runApp(new MyApp());
//Stateless widgets 是不可变的, 这意味着它们的属性不能改变 - 所有的值都是最终的.
//Stateful widgets 持有的状态可能在widget生命周期中发生变化. 实现一个 stateful widget 至少需要两个类:
class MyApp extends StatelessWidget {
final textStyleAssetFont1 = const TextStyle(
height: 0.5,
);
@override
Widget build(BuildContext context) {
// final wordPair = new WordPair.random();
return new MaterialApp(
title: 'Welcome to Flutter',
debugShowCheckedModeBanner: false,
theme: new ThemeData(
primarySwatch: Colors.blue,
// fontFamily: 'fontdemo1'
),
home: new Scaffold(
appBar: new AppBar(
title: new Text('图片加载'),
),
body: new Center(
child: new Column(
crossAxisAlignment: CrossAxisAlignment.center,
// mainAxisAlignment: MainAxisAlignment.start,
children: <Widget>[
// CustomScrollView(
// slivers: <Widget>[
//
// ],
// ),
new Text(
"",
style: textStyleAssetFont1,
),
new Image(
image: AssetImage("assets/images/food01.jpeg"),
fit: BoxFit.fill,
width: 120.0,
),
new Text(
"",
style: textStyleAssetFont1,
),
new Image.asset(
"assets/images/food02.jpeg",
width: 120.0,
fit: BoxFit.cover,
),
new Text(
"",
style: textStyleAssetFont1,
),
new Image(
image: NetworkImage(
"https://s1.51cto.com/images/20190423/1556012017949570.png"),
width: 120.0,
fit: BoxFit.contain,
),
new Text(
"",
style: textStyleAssetFont1,
),
new Image.network(
"https://s1.51cto.com/images/20190423/1556012017949570.png",
width: 120.0,
fit: BoxFit.fill,
),
new Text(
"",
style: textStyleAssetFont1,
),
Row(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Icon(
Icons.accessible,
color: Colors.green,
),
Icon(
Icons.error,
color: Colors.green,
),
Icon(
Icons.fingerprint,
color: Colors.green,
),
],
),
Row(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Icon(
MyIcons.qq,
color: Colors.red,
),
Icon(
MyIcons.wechat,
color: Colors.green,
),
],
)
],
),
),
),
);
}
}
class MyIcons {
// book 图标
static const IconData qq =
const IconData(0xe606, fontFamily: 'iconfont', matchTextDirection: true);
// 微信图标
static const IconData wechat =
const IconData(0xe607, fontFamily: 'iconfont', matchTextDirection: true);
}
4.单选开关和复选框:
import 'package:flutter/material.dart';
void main() => runApp(new MyApp());
//Stateless widgets 是不可变的, 这意味着它们的属性不能改变 - 所有的值都是最终的.
//Stateful widgets 持有的状态可能在widget生命周期中发生变化. 实现一个 stateful widget 至少需要两个类:
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
// TODO: implement build
return new MaterialApp(
title: "单选框和复选框",
home: new Scaffold(
appBar: new AppBar(
title: new Text("单选框和复选框"),
),
body: new Center(
child: new SwitchAndCheckBoxTestRoute(),
),
),
);
}
}
class SwitchAndCheckBoxTestRoute extends StatefulWidget {
@override
State<StatefulWidget> createState() {
// TODO: implement createState
return new _SwitchAndCheckBoxTestRoute();
}
}
class _SwitchAndCheckBoxTestRoute extends State<SwitchAndCheckBoxTestRoute> {
bool _switchSelected = true;
bool _checkboxSelected = true;
@override
Widget build(BuildContext context) {
// TODO: implement build
return new Column(
children: <Widget>[
Switch(
value: _switchSelected,
activeColor: Colors.blue,
inactiveThumbColor: Colors.lightBlueAccent,
onChanged: (value) {
setState(() {
_switchSelected = value;
});
},
),
Checkbox(
value: _checkboxSelected,
activeColor: Colors.red,
onChanged: (value) {
setState(() {
_checkboxSelected = value;
});
},
),
],
);
}
}
5.输入框和表单:这块比较复杂,我在学习过程中遇到很多问题,找到了一些方案,最常见的就是布局问题,键盘遮挡,目前找到的这个方案比较合适,希望能帮到你~
解决遮挡的基类:
/**
* 作者:Created by H on 2019/1/23 11:08.
* 介绍: 解决输入框被遮挡问题
*/
import 'package:flutter/material.dart';
import 'package:flutter/rendering.dart';
///
/// Helper class that ensures a Widget is visible when it has the focus
/// For example, for a TextFormField when the keyboard is displayed
///
/// How to use it:
///
/// In the class that implements the Form,
/// Instantiate a FocusNode
/// FocusNode _focusNode = new FocusNode();
///
/// In the build(BuildContext context), wrap the TextFormField as follows:
///
/// new EnsureVisibleWhenFocused(
/// focusNode: _focusNode,
/// child: new TextFormField(
/// ...
/// focusNode: _focusNode,
/// ),
/// ),
///
/// Initial source code written by Collin Jackson.
/// Extended (see highlighting) to cover the case when the keyboard is dismissed and the
/// user clicks the TextFormField/TextField which still has the focus.
///
class EnsureVisibleWhenFocused extends StatefulWidget {
const EnsureVisibleWhenFocused({
Key key,
@required this.child,
@required this.focusNode,
this.curve: Curves.ease,
this.duration: const Duration(milliseconds: 100),
}) : super(key: key);
/// The node we will monitor to determine if the child is focused
final FocusNode focusNode;
/// The child widget that we are wrapping
final Widget child;
/// The curve we will use to scroll ourselves into view.
///
/// Defaults to Curves.ease.
final Curve curve;
/// The duration we will use to scroll ourselves into view
///
/// Defaults to 100 milliseconds.
final Duration duration;
@override
_EnsureVisibleWhenFocusedState createState() => new _EnsureVisibleWhenFocusedState();
}
///
/// We implement the WidgetsBindingObserver to be notified of any change to the window metrics
///
class _EnsureVisibleWhenFocusedState extends State<EnsureVisibleWhenFocused> with WidgetsBindingObserver {
@override
void initState(){
super.initState();
widget.focusNode.addListener(_ensureVisible);
WidgetsBinding.instance.addObserver(this);
}
@override
void dispose(){
WidgetsBinding.instance.removeObserver(this);
widget.focusNode.removeListener(_ensureVisible);
super.dispose();
}
///
/// This routine is invoked when the window metrics have changed.
/// This happens when the keyboard is open or dismissed, among others.
/// It is the opportunity to check if the field has the focus
/// and to ensure it is fully visible in the viewport when
/// the keyboard is displayed
///
@override
void didChangeMetrics(){
if (widget.focusNode.hasFocus){
_ensureVisible();
}
}
///
/// This routine waits for the keyboard to come into view.
/// In order to prevent some issues if the Widget is dismissed in the
/// middle of the loop, we need to check the "mounted" property
///
/// This method was suggested by Peter Yuen (see discussion).
///
Future<Null> _keyboardToggled() async {
if (mounted){
EdgeInsets edgeInsets = MediaQuery.of(context).viewInsets;
while (mounted && MediaQuery.of(context).viewInsets == edgeInsets) {
await new Future.delayed(const Duration(milliseconds: 10));
}
}
return;
}
Future<Null> _ensureVisible() async {
// Wait for the keyboard to come into view
await Future.any([new Future.delayed(const Duration(milliseconds: 300)), _keyboardToggled()]);
// No need to go any further if the node has not the focus
if (!widget.focusNode.hasFocus){
return;
}
// Find the object which has the focus
final RenderObject object = context.findRenderObject();
final RenderAbstractViewport viewport = RenderAbstractViewport.of(object);
assert(viewport != null);
// Get the Scrollable state (in order to retrieve its offset)
ScrollableState scrollableState = Scrollable.of(context);
assert(scrollableState != null);
// Get its offset
ScrollPosition position = scrollableState.position;
double alignment;
if (position.pixels > viewport.getOffsetToReveal(object, 0.0).offset) {
// Move down to the top of the viewport
alignment = 0.0;
} else if (position.pixels < viewport.getOffsetToReveal(object, 1.0).offset){
// Move up to the bottom of the viewport
alignment = 1.0;
} else {
// No scrolling is necessary to reveal the child
return;
}
position.ensureVisible(
object,
alignment: alignment,
duration: widget.duration,
curve: widget.curve,
);
}
@override
Widget build(BuildContext context) {
return widget.child;
}
}
如何使用:
import 'package:flutter/material.dart';
import 'main15.dart';
void main() => runApp(new MyApp());
//Stateless widgets 是不可变的, 这意味着它们的属性不能改变 - 所有的值都是最终的.
//Stateful widgets 持有的状态可能在widget生命周期中发生变化. 实现一个 stateful widget 至少需要两个类:
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
// TODO: implement build
return new MaterialApp(
title: "输入框及表单",
home: new Scaffold(
appBar: new AppBar(
title: new Text("输入框及表单"),
),
body: new Center(
// child: new FormTestRoute(),
child: new TestPage(),
),
),
);
}
}
class TestPage extends StatefulWidget {
@override
_TestPageState createState() => new _TestPageState();
}
class _TestPageState extends State<TestPage> {
final GlobalKey<FormState> _formKey = new GlobalKey<FormState>();
FocusNode _focusNodeFirstName = new FocusNode();
FocusNode _focusNodeLastName = new FocusNode();
FocusNode _focusNodeDescription = new FocusNode();
static final TextEditingController _firstNameController =
new TextEditingController();
static final TextEditingController _lastNameController =
new TextEditingController();
static final TextEditingController _pwdController =
new TextEditingController();
static final TextEditingController _descriptionController =
new TextEditingController();
@override
Widget build(BuildContext context) {
return new Scaffold(
// appBar: new AppBar(
// title: new Text('My Test Page'),
// ),
body: new SafeArea(
top: false,
bottom: false,
child: new Form(
key: _formKey, //设置globalKey,用于后面获取FormState
autovalidate: true, //开启自动校验
child: new SingleChildScrollView(
padding: const EdgeInsets.symmetric(horizontal: 16.0),
child: new Column(
crossAxisAlignment: CrossAxisAlignment.stretch,
children: <Widget>[
/* -- Something large -- */
Container(
width: double.infinity,
height: 150.0,
color: Colors.red,
),
/* -- First Name -- */
new EnsureVisibleWhenFocused(
focusNode: _focusNodeFirstName,
child: new TextFormField(
decoration: const InputDecoration(
border: const UnderlineInputBorder(),
filled: true,
icon: const Icon(Icons.person),
labelText: "用户名",
hintText: "用户名或邮箱",
),
// 校验用户名
validator: (v) {
return v.trim().length > 0 ? null : "用户名不能为空";
},
onSaved: (String value) {
//TODO
},
controller: _firstNameController,
focusNode: _focusNodeFirstName,
),
),
const SizedBox(height: 24.0),
/* -- Last Name -- */
new EnsureVisibleWhenFocused(
focusNode: _focusNodeLastName,
child: new TextFormField(
decoration: const InputDecoration(
border: const UnderlineInputBorder(),
filled: true,
icon: const Icon(Icons.lock),
labelText: "密码",
hintText: "您的登录密码",
),
obscureText: true,
//校验密码
validator: (v) {
return v.trim().length > 5 ? null : "密码不能少于6位";
},
onSaved: (String value) {
//TODO
},
// controller: _lastNameController,
controller: _pwdController,
focusNode: _focusNodeLastName,
),
),
const SizedBox(height: 24.0),
/* -- Some other fields -- */
new Container(
width: double.infinity,
height: 250.0,
color: Colors.blue,
),
/* -- Description -- */
new EnsureVisibleWhenFocused(
focusNode: _focusNodeDescription,
child: new TextFormField(
decoration: const InputDecoration(
border: const OutlineInputBorder(),
hintText: '请介绍一下自己',
labelText: '简介',
),
onSaved: (String value) {
//TODO
},
maxLines: 5,
controller: _descriptionController,
focusNode: _focusNodeDescription,
),
),
const SizedBox(height: 24.0),
/* -- Save Button -- */
new Center(
child: new RaisedButton(
child: const Text('确定'),
onPressed: () {
//TODO
if ((_formKey.currentState as FormState).validate()) {
//验证通过提交数据
}
},
),
),
const SizedBox(height: 24.0),
],
),
),
),
),
);
}
}
//class FormTestRoute extends StatefulWidget {
// @override
// _FormTestRouteState createState() => new _FormTestRouteState();
//}
//
//class _FormTestRouteState extends State<FormTestRoute> {
// TextEditingController _unameController = new TextEditingController();
// TextEditingController _pwdController = new TextEditingController();
// GlobalKey _formKey = new GlobalKey<FormState>();
// FocusNode _focusNode = new FocusNode();
//
// @override
// Widget build(BuildContext context) {
// return Scaffold(
title: "Form Test",
//
// body: Padding(
// padding: const EdgeInsets.symmetric(vertical: 16.0, horizontal: 24.0),
// child: Form(
// key: _formKey, //设置globalKey,用于后面获取FormState
// autovalidate: true, //开启自动校验
// child: Column(
// children: <Widget>[
// new EnsureVisibleWhenFocused(
// focusNode: _focusNode,
// child: new TextFormField(
// autofocus: true,
// controller: _unameController,
// decoration: InputDecoration(
// labelText: "用户名",
// hintText: "用户名或邮箱",
// icon: Icon(Icons.person)),
// // 校验用户名
// validator: (v) {
// return v.trim().length > 0 ? null : "用户名不能为空";
// },
// focusNode: _focusNode,
// ),
// ),
// new EnsureVisibleWhenFocused(
// focusNode: _focusNode,
// child: new TextFormField(
// controller: _pwdController,
// decoration: InputDecoration(
// labelText: "密码",
// hintText: "您的登录密码",
// icon: Icon(Icons.lock)),
// obscureText: true,
// //校验密码
// validator: (v) {
// return v.trim().length > 5 ? null : "密码不能少于6位";
// },
// focusNode: _focusNode,
// ),
// ),
TextFormField(
autofocus: true,
controller: _unameController,
decoration: InputDecoration(
labelText: "用户名",
hintText: "用户名或邮箱",
icon: Icon(Icons.person)),
// 校验用户名
validator: (v) {
return v.trim().length > 0 ? null : "用户名不能为空";
},
),
TextFormField(
controller: _pwdController,
decoration: InputDecoration(
labelText: "密码",
hintText: "您的登录密码",
icon: Icon(Icons.lock)),
obscureText: true,
//校验密码
validator: (v) {
return v.trim().length > 5 ? null : "密码不能少于6位";
},
),
// // 登录按钮
// Padding(
// padding: const EdgeInsets.only(top: 28.0),
// child: Row(
// children: <Widget>[
// Expanded(
// child: RaisedButton(
// padding: EdgeInsets.all(15.0),
// child: Text("登录"),
// color: Theme.of(context).primaryColor,
// textColor: Colors.white,
// onPressed: () {
// //在这里不能通过此方式获取FormState,context不对
// //print(Form.of(context));
//
// // 通过_formKey.currentState 获取FormState后,
// // 调用validate()方法校验用户名密码是否合法,校验
// // 通过后再提交数据。
// if ((_formKey.currentState as FormState).validate()) {
// //验证通过提交数据
// }
// },
// ),
// ),
// ],
// ),
// )
// ],
// ),
// ),
// ),
// );
// }
//}
需要注意的是自定义布局的时候要保证开启全局校验,还有就是官方的PageScaffold目前没找到,可能是官方废弃了吧,后续再看,可以用Scaffold替换,另外还有自定义样式的写法BoxDecoration是关键,可以查查资料结合下面的代码修改,基本可以搞定一般的不带动画的需求~
import 'package:flutter/material.dart';
void main() => runApp(new MyApp());
//Stateless widgets 是不可变的, 这意味着它们的属性不能改变 - 所有的值都是最终的.
//Stateful widgets 持有的状态可能在widget生命周期中发生变化. 实现一个 stateful widget 至少需要两个类:
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
// TODO: implement build
return new MaterialApp(
title: "输入框及表单",
home: new Scaffold(
appBar: new AppBar(
title: new Text("输入框及表单"),
),
body: new Center(
child: new FormTestRoute(),
),
),
);
}
}
class FormTestRoute extends StatefulWidget {
@override
_FormTestRouteState createState() => new _FormTestRouteState();
}
class _FormTestRouteState extends State<FormTestRoute> {
TextEditingController _unameController = new TextEditingController();
TextEditingController _pwdController = new TextEditingController();
GlobalKey _formKey = new GlobalKey<FormState>();
FocusNode _focusNode = new FocusNode();
@override
Widget build(BuildContext context) {
return Scaffold(
// title: "Form Test",
body: Container(
padding: const EdgeInsets.symmetric(vertical: 16.0, horizontal: 24.0),
decoration: BoxDecoration(
// 下滑线浅灰色,宽度1像素
border: Border(
bottom: BorderSide(color: Colors.grey[200], width: 1.0))),
child: Form(
key: _formKey, //设置globalKey,用于后面获取FormState
autovalidate: true, //开启自动校验
child: Column(
children: <Widget>[
TextFormField(
autofocus: true,
controller: _unameController,
decoration: InputDecoration(
labelText: "用户名",
hintText: "用户名或邮箱",
icon: Icon(Icons.person),
border: InputBorder.none, //隐藏下划线
),
// 校验用户名
validator: (v) {
return v.trim().length > 0 ? null : "用户名不能为空";
},
),
TextFormField(
controller: _pwdController,
decoration: InputDecoration(
labelText: "密码",
hintText: "您的登录密码",
icon: Icon(Icons.lock)),
obscureText: true,
//校验密码
validator: (v) {
return v.trim().length > 5 ? null : "密码不能少于6位";
},
),
// 登录按钮
Padding(
padding: const EdgeInsets.only(top: 28.0),
child: Row(
children: <Widget>[
Expanded(
child: RaisedButton(
padding: EdgeInsets.all(15.0),
child: Text("登录"),
color: Theme.of(context).primaryColor,
textColor: Colors.white,
onPressed: () {
//在这里不能通过此方式获取FormState,context不对
//print(Form.of(context));
// 通过_formKey.currentState 获取FormState后,
// 调用validate()方法校验用户名密码是否合法,校验
// 通过后再提交数据。
if ((_formKey.currentState as FormState).validate()) {
//验证通过提交数据
}
},
),
),
],
),
)
],
),
),
),
);
}
}
总结:因为周末了,所以今天讲的有点多,可以慢慢敲一遍,你会发现dart是真心强,用的舒服~撸起袖子,继续更新ing~
转载于:https://blog.51cto.com/liangxiao/2385077