Flutter第三期 - 基礎控件demo1

開始學習一門全新的語言確實很慢,需要了解很多控件,個人的做法是大家都記不住這麼多,所以就要做一個件事,那就是寫博客,把你看到的情況都列出來,這樣你遇到需求的時候就去翻翻控件那一篇,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'),
 ),
 ),
 );
 }
}
Flutter第三期 - 基礎控件demo1

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 createState() {
 // TODO: implement createState
 return new _MyHomePageState();
 }
}
class _MyHomePageState extends State {
 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: [
 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: [
 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,
 ),
 ],
 ),
 ),
 ],
 ),
 ),
 );
 }
}
Flutter第三期 - 基礎控件demo1

需要注意的是路徑要對:

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>Flutter第三期 - 基礎控件demo1

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: [
// CustomScrollView(
// slivers: [
//
// ],
// ),
 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: [
 Icon(
 Icons.accessible,
 color: Colors.green,
 ),
 Icon(
 Icons.error,
 color: Colors.green,
 ),
 Icon(
 Icons.fingerprint,
 color: Colors.green,
 ),
 ],
 ),
 Row(
 mainAxisAlignment: MainAxisAlignment.center,
 children: [
 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);
}
Flutter第三期 - 基礎控件demo1

Flutter第三期 - 基礎控件demo1

Flutter第三期 - 基礎控件demo1

Flutter第三期 - 基礎控件demo1

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 createState() {
 // TODO: implement createState
 return new _SwitchAndCheckBoxTestRoute();
 }
}
class _SwitchAndCheckBoxTestRoute extends State {
 bool _switchSelected = true;
 bool _checkboxSelected = true;
 @override
 Widget build(BuildContext context) {
 // TODO: implement build
 return new Column(
 children: [
 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;
 });
 },
 ),
 ],
 );
 }
}
Flutter第三期 - 基礎控件demo1

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 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 _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 _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 {
 final GlobalKey _formKey = new GlobalKey();
 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: [
 /* -- 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 {
// TextEditingController _unameController = new TextEditingController();
// TextEditingController _pwdController = new TextEditingController();
// GlobalKey _formKey = new GlobalKey();
// 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: [
// 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: [
// 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()) {
// //驗證通過提交數據
// }
// },
// ),
// ),
// ],
// ),
// )
// ],
// ),
// ),
// ),
// );
// }
//}
 
Flutter第三期 - 基礎控件demo1

需要注意的是自定義佈局的時候要保證開啟全局校驗,還有就是官方的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 {
 TextEditingController _unameController = new TextEditingController();
 TextEditingController _pwdController = new TextEditingController();
 GlobalKey _formKey = new GlobalKey();
 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: [
 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: [
 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()) {
 //驗證通過提交數據
 }
 },
 ),
 ),
 ],
 ),
 )
 ],
 ),
 ),
 ),
 );
 }
}
 
Flutter第三期 - 基礎控件demo1

總結:因為週末了,所以今天講的有點多,可以慢慢敲一遍,你會發現dart是真心強,用的舒服~擼起袖子,繼續更新ing~

Flutter第三期 - 基礎控件demo1


分享到:


相關文章: