Flutter基础Widget--文本框、图片、输入框和表单

前言

从本文我们就开始介绍具体的 Widget了,先介绍文本框、图片、输入框和表单。

1. 文本框--Text 和 RichText

Text

  • 作用:显示文本的 Widget。
  • 使用:
    (1)必选参数 data:Text 的内容
Text("Hello Flutter");// Text 里传入要显示的文字

(2)可选参数 TextStyle:用来定义 Text 显示的样式,如颜色、大小、背景色等

Text(
    "Hello Flutter",
    style: TextStyle(
        color: Colors.red,
        fontSize: 20.0,
        background: new Paint()..color = Colors.yellow,
        ),
    )
  • 代码示例:
import 'package:flutter/material.dart';

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

class TextWidget extends StatelessWidget{
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: "Flutter Demo",
      theme: ThemeData(
        primaryColor: Colors.blue,
      ),
      home: Scaffold(
          appBar: AppBar(title: Text("Flutter UI基础Widget -- 文本")),
          body: Text("Hello Flutter",
          style: TextStyle(
            color: Colors.red,
            fontSize: 20.0,
            background: new Paint()..color = Colors.yellow,
          ),)
      ),
    );
  }
}
  • 运行结果:


  • Text 的其他参数
    看一下 Text 的构造函数:

class Text extends StatelessWidget {

  const Text(this.data, {
    Key key, // 选填参数,Key类型,Widget的标识,
    this.style, // 选填参数,TextStyle类型,文本样式
    this.strutStyle, // 选填参数,StrutStyle类型,设置每行的最小行高
    this.textAlign, // 选填参数,TextAlign类型,文本的对齐方式
    this.textDirection, // 选填参数,TextDirection类型,文字方向
    this.locale, // 选填参数,Local类型,用于选择用户语言和格式设置首选项的标识符
    this.softWrap, // 选填参数,bool类型,是否支持软换行符,如果是 false 的话,这个文本只有一行,水平方向是无限的
    this.overflow, // 选填参数,TextOverflow类型,文本的截断方式
    this.textScaleFactor, // 选填参数,double类型,代表文本相对于当前字体大小的缩放因子,默认值为1.0
    this.maxLines, // 选填参数,int类型,显示的最大行数
    this.semanticsLabel, // 选填参数,String类型,给文本加上一个语义标签(用不到)
  }) : assert(data != null),
       textSpan = null,
       super(key: key);
    
    ...
}

(1)textAlign:
文本的对齐方式,有六种:
TextAlign.left:左对齐
TextAlign.right:右对齐
TextAlign.center:居中对齐
TextAlign.start:从文字开始的那个方向对齐,如果文字方向从左到右,就左对齐,否则是右对齐
TextAlign.end:从文字开始的相反方向对齐,如果文字方向从左到右,就右对齐,否则是左对齐
TextAlign.justify

(2)textDirection:
文字方向,有两种:
TextDirection.ltr:文字方向从左到右
TextDirection. rtl:文字方向从右到左

(3)overflow:
文本的截断方式,有三种:
TextOverflow.ellipsis:多余文本截断后以省略符“...”表示
TextOverflow.clip:剪切多余文本,多余文本不显示
TextOverflow.fade:将多余的文本设为透明

  • TextStyle 的构造参数
class TextStyle extends Diagnosticable {

  const TextStyle({
    this.inherit = true, // 可选,类型 bool,是否继承父 Text 的样式,默认为 true,如果为 false,且样式没有设置具体的值,则采用默认值:白色、大小 10px、sans-serif 字体
    this.color, // 可选,类型 Color,文字的颜色
    this.fontSize, // 可选,类型 Color,文字的大小
    this.fontWeight, // 可选,类型 FontWeight,字体粗细
    this.fontStyle, // 可选,类型 FontStyle,是否在字体中倾斜字形
    this.letterSpacing, // 可选,类型 double,字母之间的间隔
    this.wordSpacing, // 可选,类型 double,字母之间的间隔
    this.textBaseline, // 可选,类型 TextBaseLine,用于对齐文本的水平线
    this.height, // 可选,类型 double,文本的高度,但它并不是一个绝对值,而是一个因子,具体的行高等于 fontSize * height
    this.locale, // 可选,类型 Locale,用于选择用户语言和格式设置首选项的标识符
    this.foreground, // 可选,类型 Paint,文本的前景色
    this.background, // 可选,类型 Paint,文本的背景色
    this.shadows, // 可选,类型 List<ui.Shadow>,在文本下方绘制阴影
    this.decoration, // 可选,类型 TextDecoration,文本的线条
    this.decorationColor, // 可选,类型 Color,TextDecoration 线条的颜色
    this.decorationStyle, // 可选,类型 TextDecorationStyle,TextDecoration 线条的样式
    this.debugLabel, // 可选,类型 String,文本样式的描述
    String fontFamily, // 可选,类型 String,用于设置使用那种自定义字体
    List<String> fontFamilyFallback, // 可选,类型 String,字体列表,当前面的字体找不到时,会在这个列表里依次查找
    String package, // 可选,类型 String
  }) : fontFamily = package == null ? fontFamily : 'packages/$package/$fontFamily',
       _fontFamilyFallback = fontFamilyFallback,
       _package = package,
       assert(inherit != null),
       assert(color == null || foreground == null, _kColorForegroundWarning);
       
    ...
}

RichText

  • 作用:可以显示多种样式的富文本Text。
  • 代码示例:
import 'package:flutter/material.dart';

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

class RichTextWidget extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: "Flutter Demo",
      theme: ThemeData(
        primaryColor: Colors.blue,
      ),
      home: Scaffold(
          appBar: AppBar(title: Text("Flutter UI基础Widget -- 文本")),
          body: RichText(
            text: TextSpan(children: [
              TextSpan(text: "Hello", style: TextStyle(color: Colors.blue)),
              TextSpan(text: "Flutter", style: TextStyle(color: Colors.red))
            ]),
          )),
    );
  }
}
  • 运行结果:


  • RichText 必选参数:TextSpan
    如果需要对一个 Text 内容的不同部分按照不同的样式显示,这时就可以使用 TextSpan,它代表文本的一个片段,然后把不同的 TextSpan 组合起来。

TextSpan 的构造函数及参数说明:

class TextSpan extends DiagnosticableTree {
  const TextSpan({
    this.style, // 可选,类型 TextStyle,文本样式
    this.text, // 可选,类型 String,要显示的文字
    this.children, // 可选,类型 List<TextSpan>,子TextSpan
    this.recognizer, // 可选,类型 GestureRecognizer,一个手势识别器,它将接收到达此文本范围的事件
  });
  ...
}
  • RichText 其余参数:
class RichText extends LeafRenderObjectWidget {

 const RichText({
   Key key,   // 可选,类型 Key,Widget 的标识
   @required this.text,  // 必选,类型 TextSpan,文字片段
   this.textAlign = TextAlign.start,  // 可选,类型 TextAlign,文本的对齐方式
   this.textDirection,  // 可选,类型 TextDirection,文字方向
   this.softWrap = true,  // 可选,类型 bool,是否支持换行
   this.overflow = TextOverflow.clip,  // 可选,类型 TextOverflow,文本的截断方式
   this.textScaleFactor = 1.0,  // 可选,类型 double,字体大小的缩放因子
   this.maxLines,  // 可选,类型 int,显示的最大行数
   this.locale,  // 可选,类型 Locale,用于选择用户语言和格式设置首选项的标识符
   this.strutStyle,  // 可选,类型 StrutStyle,设置每行的最小行高
 }) : assert(text != null),  
 ...
}

2. 图片和Icon--Image 和 Icon

Image

  • 作用:显示图片的 Widget。
  • 使用:
    (1)Image.asset 的使用
    第一步:将本地图片资源添加到Flutter APP
    ① 在 Flutter 工程的根目录下创建一个 images 目录,然后将一张图片拷贝到该目录;
    ② 打开 pubspec.xml,在 flutter 中添加图片的配置信息:
    方式一,一张一张添加:
flutter:
  uses-material-design: true
    
  assets:
    - images/flutter.png

方式二,可以把整个目录配置上,就不用一张张图片添加了:

flutter:
  uses-material-design: true
    
  assets:
    - images/

③ 加载图片:

Image.asset("images/flutter.png"),//显示本地资源图片

(2)Image.network 的使用

Image.network(imageUrl),//显示网络图片

(3)Image.file 的使用

Image.file(file),// 显示文件图片

(4)Image.memory 的使用

Image.memory(bytes), // 显示内存图片

Icon

  • 作用:将图标做成字体文件,然后通过指定不同的字符而显示不同的图片。

  • 和 Image 相比的优势:
    ① 体积小:可减少安装包大小。
    ② 矢量的:iconfont 都是矢量图标,放大不会影响其清晰度。
    ③ 可以应用文本样式:改变字体图标的颜色、大小对齐等。
    ④ 可以通过 TextSpan 和文本混用

  • 使用:

Icon(
  Icons.android,
  size: 50.0,
  color: Colors.green,
)

3. 输入框和表单--TextField 和 Form

TextField

  • 作用:文本输入框。
  • 使用:
TextField();
  • 获取 TextField 的内容
    (1)onChanged
    TextField的内容发生变化时,就会调用它的 onChanged 回调,我们可以在 onChanged 中获取它的内容。
TextField(
    onChanged: (String data) {
      //实时获取
      print(data);
    },
  )

(2)TextEditingController
TextEditingController 是 TextField 的控制类,可以控制 TextField 的编辑,是 TextField 的controller 属性,我们可以为 TextField 赋值自己创建的 TextEditingController 对象来控制 TextField。

class TextFieldWidget extends StatelessWidget {
  final TextEditingController _controller = TextEditingController();

  @override
  Widget build(BuildContext context) {
    return 
        ...
        TextField(
            controller: _controller,
        ),
        ...
    );
  }
}

然后使用 _controller.text 来访问 TextField 里的内容。

Form

  • 作用:是用来对输入的信息进行校验的。
  • 使用:From 是将多个表单元素组合起来的一个容器,可以将多个表单元素合并起来一起校验。
    表单元素的 Widget 是 FormField 及其子类,最常用的是以下两个:
    (1)DropdownButtonFormField
    (2)TextFormField
    使用方法:
    第一步:创建From,并为其添加 GlobalKey。
import 'package:flutter/material.dart';

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

class FormWidget extends StatefulWidget {
  @override
  State<StatefulWidget> createState() {
    // TODO: implement createState
    return FormWidgetState();
  }
}

class FormWidgetState extends State<FormWidget> {
  final GlobalKey<FormState> _formKey = GlobalKey<FormState>();

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: "Flutter Demo",
      theme: ThemeData(
        primaryColor: Colors.blue,
      ),
      home: Scaffold(
          appBar: AppBar(title: Text("Flutter UI基础Widget -- Form")),
          body: Form(
            key: _formKey, // 创建From,并为其添加 GlobalKey
            child: ...
          )),
    );
  }
}

第二步:在 From 里添加表单元素,并给表单元素添加校验逻辑。

Form(
    key: _formKey,
    child: Column(
      children: <Widget>[
        DropdownButtonFormField<String>(
          value: _userGender,
          items: ['男', '女']
              .map((label) => DropdownMenuItem(
                    child: Text(label),
                    value: label,
                  ))
              .toList(),
          onChanged: (value){
            setState(() {
              _userGender = value;
            });
          },
          onSaved: (value){
            _userGender = value;
          },
        ),
        TextFormField(
          decoration: InputDecoration(hintText: '用户名'),
          validator: (value) { // 校验
            if (value?.length <= 5) {
              return '用户名必须大于 5 个字符';
            }
          },
          onSaved: (value) {
            _userName = value;
          },
        ),
        TextFormField(
          decoration: InputDecoration(hintText: '密码'),
          obscureText: true,
          validator: (value) {
            if (value?.length <= 8) {// 校验
              return '密码必须大于 8 个字符';
            }
          },
          onSaved: (value) {
            _userPassword = value;
          },
        )
      ],
    ),
  )),

validator
表单元素的验证逻辑是 validator 函数,当表单元素的 value 值,当校验不符合时,就返回一个 String ,这个 String 是错误提示,如果校验成功,就什么也不做。
obscureText
obscureText 设为 Ture,会隐藏当前输入的文字,用 * 代理。

第三步:添加一个按钮去提交并验证表单,提交并验证表单需要用到 Form 的 FormState 方法,Form 是 StatefulWidget,FormState 是 Form 的状态。

Form(
    child: Column(
        ...
        RaisedButton(
          child: Text('注册'),
          onPressed: () {
            if (_formKey.currentState.validate()) {
              _formKey.currentState.save();
              print(_userGender);
              print(_userName);
              print(_userPassword);
            }
          },
        )
)),

FormState 为 Form 的 State 类,可以通过 Form.of() 或 GlobalKey 获得。我们可以通过它来对 Form 的子孙 FormField 进行统一操作。常用的三个方法:
① FormState.validate():调用此方法后,会调用 Form 子孙FormField 的 validate 回调,如果有一个校验失败,则返回 false,所有校验失败项都会返回用户返回的错误提示。
② FormState.save():调用此方法后,会调用 Form 子孙FormField 的 save 回调,用于保存表单内容
③ FormState.reset():调用此方法后,会将 子孙FormField 的内容清空。

  • Form 的构造函数及参数说明
class Form extends StatefulWidget {

  const Form({
    Key key, // 可选,类型 Key,Widget的表示
    @required this.child, // 必选,类型 Widget,Form 的子 Widget
    this.autovalidate = false, // 可选,类型 bool,是否自动验证,默认为 false。当设置 true时,每次输入有变动都会验证;当设置 false 时,只有调用 FormFieldState.validate 才会验证
    this.onWillPop, // 可选,类型 WillPopCallback,决定 Form 所在的路由是否可以直接返回,这个回调回返回一个 Future 对象,如果 Future 的最终结果是 false,则当前路由不会返回;如果为 true,则会返回到上一个路由。此属性通常用于拦截返回按钮。
    this.onChanged, // 可选,类型 VoidCallback,Form 的任意一个 子 FormField 内容发生变化时会触发此回调。
  }) : assert(child != null),
       super(key: key);
    ...   
}

总结

本文我们主要介绍了文本框、图片、输入框和表单等基础的 Widget。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 206,723评论 6 481
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 88,485评论 2 382
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 152,998评论 0 344
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 55,323评论 1 279
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 64,355评论 5 374
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,079评论 1 285
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,389评论 3 400
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,019评论 0 259
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 43,519评论 1 300
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,971评论 2 325
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,100评论 1 333
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,738评论 4 324
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,293评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,289评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,517评论 1 262
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,547评论 2 354
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,834评论 2 345