flutter開發(fā) 基礎(chǔ)widget(六)

Flutter頁面-基礎(chǔ)Widget

? 在Flutter中瓦呼,幾乎所有的對象都是一個Widget咐汞,與原生開發(fā)中的控件不同的是驱显,F(xiàn)lutter中的widget的概念更廣泛腕够,它不僅可以表示UI元素衡瓶,也可以表示一些功能性的組件如:用于手勢檢測的 GestureDetector widget韧献、用于應(yīng)用主題數(shù)據(jù)傳遞的Theme等等末患。由于Flutter主要就是用于構(gòu)建用戶界面的,所以锤窑,在大多數(shù)時候阻塑,可以認(rèn)為widget就是一個控件,不必糾結(jié)于概念果复。

? Widget的功能是“描述一個UI元素的配置數(shù)據(jù)”陈莽,Widget其實并不是表示最終繪制在設(shè)備屏幕上的顯示元素,而只是顯示元素的一個配置數(shù)據(jù)虽抄。實際上走搁,F(xiàn)lutter中真正代表屏幕上顯示元素的類是Element,也就是說Widget只是描述Element的一個配置迈窟。一個Widget可以對應(yīng)多個Element私植,這是因為同一個Widget對象可以被添加到UI樹的不同部分,而真正渲染時车酣,UI樹的每一個節(jié)點都會對應(yīng)一個Element對象曲稼。

?

Widget

StatelessWidgetStatefulWidgetflutter的基礎(chǔ)組件索绪,日常開發(fā)中自定義Widget都是選擇繼承這兩者之一。也是在往后的開放中贫悄,我們最多接觸的Widget:

StatelessWidget:無狀態(tài)的瑞驱,展示信息,面向那些始終不變的UI控件窄坦;

StatefulWidget:有狀態(tài)的唤反,可以通過改變狀態(tài)使得 UI 發(fā)生變化,可以包含用戶交互(比如彈出一個 dialog)鸭津。

在實際使用中彤侍,Stateless與Stateful的選擇需要取決于這個 Widget 是有狀態(tài)還是無狀態(tài),簡單來說看界面是否需要更新逆趋。

StatelessWidget

? StatelessWidget用于不需要維護(hù)狀態(tài)的場景盏阶,它通常在build方法中通過嵌套其它Widget來構(gòu)建UI,在構(gòu)建過程中會遞歸的構(gòu)建其嵌套的Widget闻书。

BuildContext表示構(gòu)建widget的上下文名斟,它是操作widget在樹中位置的一個句柄,它包含了一些查找惠窄、遍歷當(dāng)前Widget樹的一些方法蒸眠。每一個widget都有一個自己的context對象漾橙。

import 'package:flutter/material.dart';

void main() => runApp(StatelessApp());

class StatelessApp extends StatelessWidget {
  ///在build方法中通過嵌套其它Widget來構(gòu)建UI杆融,在構(gòu)建過程中會遞歸的構(gòu)建其嵌套的Widget
  @override
  Widget build(BuildContext context) {
    //嵌套 MaterialApp:封裝了應(yīng)用程序?qū)崿F(xiàn)Material Design所需要的一些widget
    return MaterialApp(
        title: "Widget演示", //標(biāo)題,顯示在recent時候的標(biāo)題
        //主頁面
        //Scaffold : Material Design布局結(jié)構(gòu)的基本實現(xiàn)。
        home: Scaffold(
          //ToolBar/ActionBar
          appBar: AppBar(title: Text("Widget")),
          body: Text("Hello,Flutter!"),
        )
    );
  }
}

Material Design:

一種設(shè)計語言霜运,Material Design 于2014年的 Google I/O 首次亮相脾歇,是谷歌推出的全新的設(shè)計語言。說白了淘捡,就是一種設(shè)計風(fēng)格藕各。

StatefulWidget

? StatefulWidget是動態(tài)的,添加了一個新的接口createState()用于創(chuàng)建和Stateful widget相關(guān)的狀態(tài)State焦除,它在Stateful widget的生命周期中可能會被多次調(diào)用激况。

? 當(dāng)State被改變時,可以手動調(diào)用其setState()方法通知Flutter framework狀態(tài)發(fā)生改變膘魄,F(xiàn)lutter framework在收到消息后乌逐,會重新調(diào)用其build方法重新構(gòu)建widget樹,從而達(dá)到更新UI的目的创葡。

class StatefulState extends State<StatefulApp> {
  int _i;

  ///當(dāng)Widget第一次插入到Widget樹時會被調(diào)用浙踢,對于每一個State對象,F(xiàn)lutter framework只會調(diào)用一次該回調(diào)
  @override
  void initState() {
    super.initState();
    _i = 1;
  }

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
        title: "Widget演示",
        theme: ThemeData(),
        home: Scaffold(
          appBar: AppBar(title: Text("Widget")),
          body: RaisedButton(
            onPressed: () {
              //修改狀態(tài)灿渴,setState會重新調(diào)用build更新ui
              setState(() {
                _i++;
              });
            },
            child: Text("Hello,Flutter! $_i"),
          ),
        ));
  }
}

State生命周期

State的生命周期為:

生命周期.png

? State類除了build之外還提供了很多方法能夠讓我們重寫洛波,這些方法會在不同的狀態(tài)下由Flutter調(diào)起執(zhí)行胰舆,所以這些方法我們就稱之為生命周期方法。在這里我們用statefulwidget點擊按鈕后移除子statefulwidget蹬挤。

import 'package:flutter/material.dart';

void main() => runApp(MyApp());

class MyApp extends StatefulWidget {
  @override
  _MyAppState createState() => _MyAppState();
}

class _MyAppState extends State<MyApp> {
  bool isShowChild;

  ///當(dāng)Widget第一次插入到Widget樹時會被調(diào)用缚窿,對于每一個State對象,F(xiàn)lutter framework只會調(diào)用一次該回調(diào)
  @override
  void initState() {
    super.initState();
    isShowChild = true;
    debugPrint("parent initState......");
  }

  ///初始化時闻伶,在initState()之后立刻調(diào)用
  ///當(dāng)依賴的InheritedWidget rebuild,會觸發(fā)此接口被調(diào)用
  @override
  void didChangeDependencies() {
    super.didChangeDependencies();
    debugPrint("parent didChangeDependencies......");
  }

  ///繪制界面滨攻,當(dāng)setState觸發(fā)的時候會再次被調(diào)用
  @override
  Widget build(BuildContext context) {
    debugPrint("parent build......");
    return MaterialApp(
      home: Scaffold(
        body: Center(
            child: RaisedButton(
          onPressed: () {
            setState(() {
              isShowChild = !isShowChild;
            });
          },
          child: isShowChild ? Child() : Text("演示移除Child"),
        )),
      ),
    );
  }

  ///狀態(tài)改變的時候會調(diào)用該方法,比如調(diào)用了setState
  @override
  void didUpdateWidget(MyApp oldWidget) {
    super.didUpdateWidget(oldWidget);
    debugPrint("parent didUpdateWidget......");
  }

  ///當(dāng)State對象從樹中被移除時,會調(diào)用此回調(diào)
  @override
  void deactivate() {
    super.deactivate();
    debugPrint('parent deactivate......');
  }

  ///當(dāng)State對象從樹中被永久移除時調(diào)用蓝翰;通常在此回調(diào)中釋放資源
  @override
  void dispose() {
    super.dispose();
    debugPrint('parent dispose......');
  }
}

class Child extends StatefulWidget {
  @override
  _ChildState createState() => _ChildState();
}

class _ChildState extends State<Child> {
  @override
  Widget build(BuildContext context) {
    debugPrint("child build......");
    return Text('lifeCycle');
  }

  @override
  void initState() {
    super.initState();
    debugPrint("child initState......");
  }

  ///初始化時光绕,在initState()之后立刻調(diào)用
  ///當(dāng)依賴的InheritedWidget rebuild,會觸發(fā)此接口被調(diào)用
  @override
  void didChangeDependencies() {
    super.didChangeDependencies();
    debugPrint("child didChangeDependencies......");
  }

  ///父widget狀態(tài)改變的時候會調(diào)用該方法,比如父節(jié)點調(diào)用了setState
  @override
  void didUpdateWidget(Child oldWidget) {
    super.didUpdateWidget(oldWidget);
    debugPrint("child didUpdateWidget......");
  }

  ///當(dāng)State對象從樹中被移除時,會調(diào)用此回調(diào)
  @override
  void deactivate() {
    super.deactivate();
    debugPrint('child deactivate......');
  }

  ///當(dāng)State對象從樹中被永久移除時調(diào)用畜份;通常在此回調(diào)中釋放資源
  @override
  void dispose() {
    super.dispose();
    debugPrint('child dispose......');
  }
}

執(zhí)行的輸出結(jié)果顯示為:

  • 運行到顯示
I/flutter (22218): parent initState......
I/flutter (22218): parent didChangeDependencies......
I/flutter (22218): parent build......
I/flutter (22218): child initState......
I/flutter (22218): child didChangeDependencies......
I/flutter (22218): child build......
  • 點擊按鈕會移除Child
I/flutter (22218): parent build......
I/flutter (22218): child deactivate......
I/flutter (22218): child dispose......
  • 將MyApp的代碼由child: isShowChild ? Child() : Text("演示移除Child")诞帐,改為child: Child(),點擊按鈕時
I/flutter (22765): parent build......
I/flutter (22765): child didUpdateWidget......
I/flutter (22765): child build......

基礎(chǔ)widget

文本顯示

Text

Text是展示單一格式的文本W(wǎng)idget(Android TextView)爆雹。

import 'package:flutter/material.dart';

///
/// main方法 調(diào)用runApp傳遞Widget停蕉,這個Widget成為widget樹的根
void main() => runApp(TextApp());

///
/// 1、單一文本Text
///
//創(chuàng)建一個無狀態(tài)的Widget
class TextApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    //封裝了應(yīng)用程序?qū)崿F(xiàn)Material Design所需要的一些widget
    return MaterialApp(
      title: "Text演示", //標(biāo)題,顯示在recent時候的標(biāo)題
      //主頁面
      //Scaffold : Material Design布局結(jié)構(gòu)的基本實現(xiàn)钙态。
      home: Scaffold(
        //ToolBar/ActionBar
        appBar: AppBar(title: Text("Text")),
        body: Text("Hello,Flutter"),
      ),
    );
  }
}

在使用Text顯示文字時候慧起,可能需要對文字設(shè)置各種不同的樣式,類似Android的 android:textColor/Size

在Flutter中也擁有類似的屬性

Widget _TextBody() {
  return Text(
    "Hello,Flutter",
    style: TextStyle(
        //顏色
        color: Colors.red,
        //字號 默認(rèn)14
        fontSize: 18,
        //粗細(xì)
        fontWeight: FontWeight.w800,
        //斜體
        fontStyle: FontStyle.italic,
        //underline:下劃線册倒,overline:上劃線蚓挤,lineThrough:刪除線
        decoration: TextDecoration.lineThrough,
        decorationColor: Colors.black,
        //solid:實線,double:雙線驻子,dotted:點虛線灿意,dashed:橫虛線,wavy:波浪線
        decorationStyle: TextDecorationStyle.wavy),
  );
}

class TextApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: "Text演示", 
      home: Scaffold(
        appBar: AppBar(title: Text("Text")),
        body: _TextBody(),
      ),
    );
  }
}
text.png

RichText

如果需要顯示更為豐富樣式的文本(比如一段文本中文字不同顏色),可以使用RichText或者Text.rich

Widget _RichTextBody() {
  var textSpan = TextSpan(
    text: "Hello",
    style: TextStyle(color: Colors.red),
    children: [
      TextSpan(text: "Flu", style: TextStyle(color: Colors.blue)),
      TextSpan(text: "uter", style: TextStyle(color: Colors.yellow)),
    ],
  );
  //Text.rich(textSpan);
  return RichText(text: textSpan);
}
RichText.png

DefaultTextStyle

? 在widget樹中崇呵,文本的樣式默認(rèn)是可以被繼承的缤剧,因此,如果在widget樹的某一個節(jié)點處設(shè)置一個默認(rèn)的文本樣式域慷,那么該節(jié)點的子樹中所有文本都會默認(rèn)使用這個樣式荒辕。相當(dāng)于在Android中定義 Theme

Widget _DefaultStyle(){
  DefaultTextStyle(
    //設(shè)置文本默認(rèn)樣式
    style: TextStyle(
      color:Colors.red,
      fontSize: 20.0,
    ),
    textAlign: TextAlign.start,
    child: Column(
      crossAxisAlignment: CrossAxisAlignment.start,
      children: <Widget>[
        Text("Hello Flutter!"),
        Text("Hello Flutter!"),
        Text("Hello Flutter!",
          style: TextStyle(
              inherit: false, //不繼承默認(rèn)樣式
              color: Colors.grey
          ),
        ),
      ],
    ),
  );
}

FlutterLogo

? 這個Widget用于顯示Flutter的logo......

Widget flutterLogo() {
  return FlutterLogo(
    //大小
    size: 100,
    //logo顏色 默認(rèn)為 Colors.blue
    colors: Colors.red,
    //markOnly:只顯示logo,horizontal:logo右邊顯示flutter文字犹褒,stacked:logo下面顯示文字
    style: FlutterLogoStyle.stacked,
    //logo上文字顏色
    textColor: Colors.blue,
  );
}
flutter.png

Icon

主要用于顯示內(nèi)置圖標(biāo)的Widget

Widget icon() {
  return Icon(
      //使用預(yù)定義Material icons
      // https://docs.flutter.io/flutter/material/Icons-class.html
      Icons.add,
      size: 100,
      color: Colors.red);
}
add.png

Image

顯示圖片的Widget抵窒。圖片常用的格式主要有bmp,jpg,png,gif,webp等,Android中并不是天生支持gif和webp動圖化漆,但是這一特性在flutter中被很好的支持了估脆。

方式 解釋
Image() 使用ImageProvider提供圖片,如下方法本質(zhì)上也是使用的這個方法
Image.asset 加載資源圖片
Image.file 加載本地圖片文件
Image.network 加載網(wǎng)絡(luò)圖片
Image.memory 加載內(nèi)存圖片
Iamge.asset

在工程目錄下創(chuàng)建目錄座云,如:assets疙赠,將圖片放入此目錄付材。打開項目根目錄:pubspec.yaml

基礎(chǔ)Widget_AssetsImag.png
return MaterialApp(
      title: "Image演示",
      home: Scaffold(
        appBar: AppBar(title: Text("Image")),
        body: Image.asset("assets/banner.jpeg"),
      ),
    );
Image.file

在sd卡中放入一張圖片。然后利用path_provider庫獲取sd卡根目錄(Dart庫版本可以在:https://pub.dartlang.org/packages查詢)圃阳。

基礎(chǔ)Widget_FileProvider.png

注意權(quán)限

class ImageState extends State<ImageApp> {
  Image image;

  @override
  void initState() {
    super.initState();
    getExternalStorageDirectory().then((path) {
      setState(() {
        image = Image.file(File("${path.path}${Platform.pathSeparator}banner.jpeg"));
      });
    });
  }

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: "Image演示",
      home: Scaffold(
        appBar: AppBar(title: Text("Image")),
        body: image,
      ),
    );
  }
}
Image.network

直接給網(wǎng)絡(luò)地址即可厌衔。

Flutter 1.0,加載https時候經(jīng)常出現(xiàn)證書錯誤捍岳。必須斷開AS打開app

Image.memory
Future<List<int>> _imageByte() async {
  String path = (await getExternalStorageDirectory()).path;
  return await File("$path${Platform.pathSeparator}banner.jpeg").readAsBytes();
}

class ImageState extends State<ImageApp> {
  Image image;

  @override
  void initState() {
    super.initState();
    _imageByte().then((bytes) {
      setState(() {
        image = Image.memory(bytes);
      });
    });
  }

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: "Image演示",
      home: Scaffold(
        appBar: AppBar(title: Text("Image")),
        body: image,
      ),
    );
  }
}

fit屬性相當(dāng)于android中的scaletype富寿,定義如下:

fit 說明 效果
BoxFit.fill 填充,忽略原有的寬高比锣夹,填滿為止 [圖片上傳失敗...(image-359f5-1562834193984)]
BoxFit.contain 包含页徐,不改變原有比例讓容器包含整個圖片,容器多余部分填充背景 [圖片上傳失敗...(image-e0264-1562834193985)]
BoxFit.cover 覆蓋银萍,不改變原有比例变勇,讓圖片充滿整個容器,圖片多余部分裁剪 [圖片上傳失敗...(image-4a0faa-1562834193985)]
BoxFit.fitWidth 橫向圖片填充 [圖片上傳失敗...(image-71c8-1562834193985)]
BoxFit.fitHeight 縱向圖片填充 [圖片上傳失敗...(image-d9b429-1562834193985)]
BoxFit.none 原始大小居中 [圖片上傳失敗...(image-dd791c-1562834193985)]
BoxFit.scaleDown 圖片大小小于容器事相當(dāng)于none贴唇,圖片大小大于容器時縮小圖片大小實現(xiàn)contain [圖片上傳失敗...(image-28ecf4-1562834193985)]

CircleAvatar

主要用來顯示用戶的頭像搀绣,任何圖片都會被剪切為圓形。

CircleAvatar(
      //圖片提供者 ImageProvider
      backgroundImage: AssetImage("assets/banner.jpeg"),
      //半徑戳气,控制大小
      radius: 50.0,
    );

FadeInImage

當(dāng)使用默認(rèn)Image widget顯示圖片時链患,您可能會注意到它們在加載完成后會直接顯示到屏幕上。這可能會讓用戶產(chǎn)生視覺突兀瓶您。如果最初顯示一個占位符麻捻,然后在圖像加載完顯示時淡入,我們可以使用FadeInImage來達(dá)到這個目的览闰!

 image =  FadeInImage.memoryNetwork(
      placeholder: kTransparentImage,
      image: 'https://flutter.io/images/homepage/header-illustration.png',
    );

按鈕

Material widget庫中提供了多種按鈕Widget如RaisedButton芯肤、FlatButton巷折、OutlineButton等压鉴,它們都是直接或間接對RawMaterialButton的包裝定制,所以他們大多數(shù)屬性都和RawMaterialButton一樣锻拘。所有Material 庫中的按鈕都有如下相同點:

  1. 按下時都會有“水波動畫”油吭。
  2. 有一個onPressed屬性來設(shè)置點擊回調(diào),當(dāng)按鈕按下時會執(zhí)行該回調(diào)署拟,如果不提供該回調(diào)則按鈕會處于禁用狀態(tài)婉宰,禁用狀態(tài)不響應(yīng)用戶點擊。

RaisedButton

"漂浮"按鈕推穷,它默認(rèn)帶有陰影和灰色背景

RaisedButton(
          child: Text("normal"),
          onPressed: () => {},
        )

FlatButton

扁平按鈕心包,默認(rèn)背景透明并不帶陰影

FlatButton(
  child: Text("normal"),
  onPressed: () => {},
)

OutlineButton

默認(rèn)有一個邊框,不帶陰影且背景透明馒铃。

OutlineButton(
  child: Text("normal"),
  onPressed: () => {},
)

IconButton

可點擊的Icon

IconButton(
  icon: Icon(Icons.thumb_up),
  onPressed: () => {},
)

按鈕外觀可以通過其屬性來定義蟹腾,不同按鈕屬性大同小異

const FlatButton({
  ...  
  @required this.onPressed, //按鈕點擊回調(diào)
  this.textColor, //按鈕文字顏色
  this.disabledTextColor, //按鈕禁用時的文字顏色
  this.color, //按鈕背景顏色
  this.disabledColor,//按鈕禁用時的背景顏色
  this.highlightColor, //按鈕按下時的背景顏色
  this.splashColor, //點擊時痕惋,水波動畫中水波的顏色
  this.colorBrightness,//按鈕主題,默認(rèn)是淺色主題 
  this.padding, //按鈕的填充
  this.shape, //外形
  @required this.child, //按鈕的內(nèi)容
})
    
FlatButton(
  onPressed: () => {},
  child: Text("Raised"),
  //藍(lán)色
  color: Colors.blue,
  //水波
  splashColor: Colors.yellow,
  //深色主題娃殖,這樣文字顏色會變成白色
  colorBrightness: Brightness.dark,
   //圓角按鈕
  shape: RoundedRectangleBorder(
      borderRadius: BorderRadius.circular(50)
  ),
)

RaisedButton值戳,默認(rèn)配置有陰影,因此在配置RaisedButton 時炉爆,擁有一系列 elevation 屬性的配置

const RaisedButton({
  ...
  this.elevation = 2.0, //正常狀態(tài)下的陰影
  this.highlightElevation = 8.0,//按下時的陰影
  this.disabledElevation = 0.0,// 禁用時的陰影
  ...
}

輸入框

import 'package:flutter/material.dart';

void main() => runApp(Demo1());

class Demo1 extends StatelessWidget {

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: "Demo1",
      home: Scaffold(
        appBar: AppBar(
          title: Text("登錄"),
        ),
        //線性布局堕虹,垂直方向
        body: Column(
          children: <Widget>[
            TextField(
              //自動獲得焦點
              autofocus: true,
              decoration: InputDecoration(
                  labelText: "用戶名",
                  hintText: "用戶名或郵箱",
                  prefixIcon: Icon(Icons.person)),
            ),
            TextField(
              //隱藏正在編輯的文本
              obscureText: true,
              decoration: InputDecoration(
                  labelText: "密碼",
                  hintText: "您的登錄密碼",
                  prefixIcon: Icon(Icons.lock)),
            ),
          ],
        ),
      ),
    );
  }
}
TextField.png

這個效果非常的“系統(tǒng)”,我們可能大多數(shù)情況下需要將下劃線更換為矩形邊框芬首,這時候可能就需要組合widget來完成:

//容器 設(shè)置一個控件的尺寸赴捞、背景、margin 
Container(
    margin: EdgeInsets.all(32),
    child: TextField(
        keyboardType: TextInputType.emailAddress,
        decoration: InputDecoration(
            labelText: "用戶名",
            hintText: "用戶名或郵箱",
            prefixIcon: Icon(Icons.person),
            border: InputBorder.none //隱藏下劃線
            )),
    //裝飾
    decoration: BoxDecoration(
      // 邊框淺灰色郁稍,寬度1像素
      border: Border.all(color: Colors.red[200], width: 1.0),
      //圓角
      borderRadius: BorderRadius.circular(5.0),
    ),
  )
組合.png

焦點控制

? FocusNode: 與Widget綁定螟炫,代表了這個Widget的焦點

? FocusScope: 焦點控制范圍

? FocusScopeNode:控制焦點

class _TextFocusState extends State<TextFocusWidget> {
  FocusNode focusNode1 = new FocusNode();
  FocusNode focusNode2 = new FocusNode();

  void _listener() {
    debugPrint("用戶名輸入框焦點:${focusNode1.hasFocus}");
  }

  @override
  void initState() {
    super.initState();
    //監(jiān)聽焦點狀態(tài)改變事件
    focusNode1.addListener(_listener);
  }

  @override
  void dispose() {
    super.dispose();
    focusNode1.dispose();
    focusNode2.dispose();
  }

  @override
  Widget build(BuildContext context) {
    return Column(
      children: <Widget>[
        TextField(
          autofocus: true,
          //關(guān)聯(lián)焦點
          focusNode: focusNode1,
          //設(shè)置鍵盤動作為: 下一步
          textInputAction: TextInputAction.next,
          //點擊下一步執(zhí)行回調(diào)
          onEditingComplete: () {
            //獲得 context對應(yīng)UI樹的焦點范圍 的焦點控制器
            FocusScopeNode focusScopeNode = FocusScope.of(context);
            //將焦點交給focusNode2
            focusScopeNode.requestFocus(focusNode2);
          },
          decoration: InputDecoration(
              labelText: "用戶名",
              hintText: "用戶名或郵箱",
              prefixIcon: Icon(Icons.person)),
        ),
        TextField(
          //隱藏正在編輯的文本
          obscureText: true,
          focusNode: focusNode2,
          decoration: InputDecoration(
              labelText: "密碼",
              hintText: "您的登錄密碼",
              prefixIcon: Icon(Icons.lock)),
        ),
        custom(),
      ],
    );
  }
}

獲取輸入內(nèi)容

獲取輸入內(nèi)容有兩種方式:

  1. 定義兩個變量,用于保存用戶名和密碼艺晴,然后在onChange觸發(fā)時昼钻,各自保存一下輸入內(nèi)容。
  2. 通過controller直接獲取封寞。

onChange獲得輸入內(nèi)容:

TextField(
      onChanged: (s) => debugPrint("ssss:$s"),
    )

controller獲取:

定義一個controller:

//定義一個controller
TextEditingController _unameController=new TextEditingController();

然后設(shè)置輸入框controller:

TextField(
    controller: _unameController, //設(shè)置controller
    ...
)

通過controller獲取輸入框內(nèi)容

debugPrint(_unameController.text)

TextFormField

TextFormFieldTextField多了一些屬性然评,其中 validator用于設(shè)置驗證回調(diào)。在單獨使用時與TextField沒有太大的區(qū)別狈究。當(dāng)結(jié)合From碗淌,利用From可以對輸入框進(jìn)行分組,然后進(jìn)行一些統(tǒng)一操作(驗證)

class _TextFocusState extends State<TextFocusWidget> {
  //全局key
  GlobalKey<FormState> _key = GlobalKey<FormState>();

  @override
  Widget build(BuildContext context) {
    return Form(
        //類似 id
        key: _key,
        child: Column(
          children: <Widget>[
            TextFormField(
                autofocus: true,
                decoration: InputDecoration(
                    labelText: "用戶名",
                    hintText: "用戶名或郵箱",
                    icon: Icon(Icons.person)),
                // 校驗用戶名
                validator: (v) {
                  return v.trim().length > 0 ? null : "用戶名不能為空";
                }),
            TextFormField(
                decoration: InputDecoration(
                    labelText: "密碼",
                    hintText: "您的登錄密碼",
                    icon: Icon(Icons.lock)),
                // 校驗用戶名
                validator: (v) {
                  return v.trim().length > 0 ? null : "密碼不能為空";
                }),
            RaisedButton(
              onPressed: () {
                //Form所有TextFormField成功 返回true
                if (_key.currentState.validate()) {
                  
                }
              },
              child: Text("提交"),
            )
          ],
        ));
  }
}
TextFormField.jpg
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末抖锥,一起剝皮案震驚了整個濱河市亿眠,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌磅废,老刑警劉巖纳像,帶你破解...
    沈念sama閱讀 218,682評論 6 507
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異拯勉,居然都是意外死亡竟趾,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,277評論 3 395
  • 文/潘曉璐 我一進(jìn)店門宫峦,熙熙樓的掌柜王于貴愁眉苦臉地迎上來岔帽,“玉大人,你說我怎么就攤上這事导绷∠眨” “怎么了?”我有些...
    開封第一講書人閱讀 165,083評論 0 355
  • 文/不壞的土叔 我叫張陵,是天一觀的道長贾费。 經(jīng)常有香客問我枚碗,道長,這世上最難降的妖魔是什么铸本? 我笑而不...
    開封第一講書人閱讀 58,763評論 1 295
  • 正文 為了忘掉前任肮雨,我火速辦了婚禮,結(jié)果婚禮上箱玷,老公的妹妹穿的比我還像新娘怨规。我一直安慰自己,他們只是感情好锡足,可當(dāng)我...
    茶點故事閱讀 67,785評論 6 392
  • 文/花漫 我一把揭開白布波丰。 她就那樣靜靜地躺著,像睡著了一般舶得。 火紅的嫁衣襯著肌膚如雪掰烟。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,624評論 1 305
  • 那天沐批,我揣著相機(jī)與錄音纫骑,去河邊找鬼。 笑死九孩,一個胖子當(dāng)著我的面吹牛先馆,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播躺彬,決...
    沈念sama閱讀 40,358評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼煤墙,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了宪拥?” 一聲冷哼從身側(cè)響起仿野,我...
    開封第一講書人閱讀 39,261評論 0 276
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎她君,沒想到半個月后脚作,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,722評論 1 315
  • 正文 獨居荒郊野嶺守林人離奇死亡犁河,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,900評論 3 336
  • 正文 我和宋清朗相戀三年鳖枕,在試婚紗的時候發(fā)現(xiàn)自己被綠了魄梯。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片桨螺。...
    茶點故事閱讀 40,030評論 1 350
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖酿秸,靈堂內(nèi)的尸體忽然破棺而出灭翔,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 35,737評論 5 346
  • 正文 年R本政府宣布肝箱,位于F島的核電站哄褒,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏煌张。R本人自食惡果不足惜呐赡,卻給世界環(huán)境...
    茶點故事閱讀 41,360評論 3 330
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望骏融。 院中可真熱鬧链嘀,春花似錦、人聲如沸档玻。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,941評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽误趴。三九已至霹琼,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間凉当,已是汗流浹背枣申。 一陣腳步聲響...
    開封第一講書人閱讀 33,057評論 1 270
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點兒被人妖公主榨干…… 1. 我叫王不留看杭,地道東北人糯而。 一個月前我還...
    沈念sama閱讀 48,237評論 3 371
  • 正文 我出身青樓,卻偏偏與公主長得像泊窘,于是被迫代替她去往敵國和親熄驼。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 44,976評論 2 355

推薦閱讀更多精彩內(nèi)容