Flutter | 常用组件(下)

简介: Flutter | 常用组件(下)

上面代码中,都行需要维护组件的状态,所以继承自 StatefulWidget ,在 build 中,构建了 checkBox 和 Switch 和 Radio,在点击的时候修改状态,然后重新构建 UI


属性


共有属性 activeColor,设置激活状态的颜色

宽高:Checkbox 无法自定义,Switch 只能定义宽度

Checkbox 有一个属性 tristate,表示是否为三态,默认值为false,如果为true 时,valude 的值会自动增加一个状态 null


总结


Switch , Checkbox 和 Radio 本身不会维护状态,而是需要父组件来管理状态,当用户点击时,通过事件将状态通知到父组件,因此是否选中就会和用户数据发生关联,而这些用户数据也不是他们的私有状态。因此,我们在自定义组件是应该思考一下那种方式最为合理


输入框和表单


Material 组件库中提供了输入框组件 TextField 和表单组件 From ,下面来具体看一下


TextField


用于文本输入,它提供了很多属性,首先简单看一下关键的属性作用


const TextField({
  ...
  TextEditingController controller, 
  FocusNode focusNode,
  InputDecoration decoration = const InputDecoration(),
  TextInputType keyboardType,
  TextInputAction textInputAction,
  TextStyle style,
  TextAlign textAlign = TextAlign.start,
  bool autofocus = false,
  bool obscureText = false,
  int maxLines = 1,
  int maxLength,
  bool maxLengthEnforced = true,
  ValueChanged<String> onChanged,
  VoidCallback onEditingComplete,
  ValueChanged<String> onSubmitted,
  List<TextInputFormatter> inputFormatters,
  bool enabled,
  this.cursorWidth = 2.0,
  this.cursorRadius,
  this.cursorColor,
  ...
})


controller :编辑框的控制器,可以通过它设置/获取编辑框的内容,选择编辑框的内容,监听编辑框文本改变事件。大多数情况下我们都需要显示的提供一个 controller 来与文本框交互,如果没有提供,则 TextField 会自动创建一个


focusNode :用于控制 TextField 是否占有当前键盘输入的焦点、他是我们和键盘交互的一个句柄(handler)。


InputDecoration:用于控制 TextField 的外观显示,如提示文本,背景颜色,边框等


keyboardType :用于设置该输入框的键盘输入类型,取值如下:

image.png

textInputAction :键盘动作按钮图标,他是一个枚举值,有多个可选值,具体的可查看 api


style:正在编辑的文本样式


textAlign:输入框内编辑文本在水平方向的对齐方式


autofocus:是否自动获取焦点.


obscureText :是否隐藏正在编辑的文本,如输入密码等。


maxLines :输入最大行数,默认为 1,如果为 null,则为无限制maxLength 和 maxLengthEnforced :前者代表输入文本的最大长度,设置后输入框右下角会显示输入的文本计数。后者决定输入长度超过 maxLength 后是否阻止


onChange:输入框内容改变的回调,也可通过 controller 来监听


onEditingComplete 和 onSubmitted :这两者都是在输入完成时触发,例如点击键盘的完成,或者搜索等。不同的是后者的回调是 ValueChanged ,前者不接受参数


inputFormatters:用于指定输入格式,当输入内容改变时,会根据指定格式来校验


enable:若为 false,则输入框被禁用


cursorWidth ,cursorRadius 和 cursorColor:定义光标的宽度,圆角和颜色


栗子


class InputText extends StatefulWidget {
  @override
  State<StatefulWidget> createState() {
    return _InputText();
  }
}
class _InputText extends State<InputText> {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text("输入框"),
      ),
      body: Column(
        children: [
          TextField(
            autocorrect: true,
            decoration: InputDecoration(
                labelText: "用户名",
                hintText: "用户名或邮箱",
                prefixIcon: Icon(Icons.person)),
          ),
          TextField(
            decoration: InputDecoration(
                labelText: "密码",
                hintText: "您的登录密码",
                prefixIcon: Icon(Icons.lock)),
            obscureText: true,
          )
        ],
      ),
    );
  }
}


获取输入内容


1,定义两个变量,则 onChange 触发的时候保存即可


2,通过 controler 直接获取


//定义一个controller
TextEditingController _nameController = TextEditingController();
1
2
TextField(
    autofocus: true,
    controller: _nameController, //设置controller
    ...
)


//直接输出即可
print(_nameController.text)


controller 还可以用来设置默认值,选择文本等


_nameController.text="hello world!";
_nameController.selection=TextSelection(
    baseOffset: 2,
    extentOffset: _nameController.text.length
);
TextField(
  controller: _nameController,
)


控制焦点


焦点可以通过 FocusNode 和 FocusScopeNode 来控制,默认情况下,焦点由FocusScope来管理,它代表焦点控制范围,可以在这个范围内可以通过FocusScopeNode在输入框之间移动焦点、设置默认焦点等。我们可以通过FocusScope.of(context) 来获取Widget树中默认的FocusScopeNode。


简单焦点状态改变事件


// 创建 focusNode   
FocusNode focusNode = new FocusNode();
...
// focusNode绑定输入框   
TextField(focusNode: focusNode);
...
// 监听焦点变化    
focusNode.addListener((){
   print(focusNode.hasFocus);
});


自定义样式


隐藏文本


TextField(
     obscureText: true,
 )


隐藏后输入的内容将不可见,变成密码类型了


键盘类型


TextField(
  keyboardType: TextInputType.number,
),


例如,number 就只能输入数字,还有很多的值,如下,可以自行查看


键盘按钮


即键盘右下角的按钮,常见的例如完成,是一个对号的按钮等


大小写


控制英文字母的大小写,比如但是首字母大写等


TextField(
  textCapitalization: TextCapitalization.words,
),


textCapitalization 的选项


1,words:单词首字母大写


2,sentences:句子首字母大写


3,characters:所有字母大写


4,none:默认无


光标


TextField(
  cursorColor: Colors.orange,//颜色
  cursorWidth: 15,//宽度
  cursorRadius: Radius.circular(15),//圆角
),


计数器


TextField(
  maxLength: 11,
),


设置最大长度计数器就可显示出来


自定义计数器/图标


TextField(
            autocorrect: true,
            maxLength: 11,
            controller: _nameController,
            decoration: InputDecoration(
                labelText: "用户名",
                hintText: "用户名或邮箱",
                counter: Text("计数器 0/100"),
                prefixIcon: Icon(Icons.person)),
          ),


通过 counter 来实现 自定义计数器


并且通过 prefixIcon 可以设置左侧内图标,通过 icon 可设置左侧外图标


decoration: InputDecoration(
  suffixIcon: IconButton(
  icon: Icon(Icons.close),
  onPressed: () {
  controller.clear();
  },
),


通过 suffixIcon 可以设置右侧内图标,并且可以设置点击事件


错误文字提示


TextField(
  controller: controller,
  decoration: InputDecoration(
  errorText: "请输入内容",
  ),
),


去除下划线


decoration: InputDecoration.collapsed(hintText: "用户名或邮箱")),


边框


decoration: InputDecoration(
              border: OutlineInputBorder(
                  borderRadius: BorderRadius.all(Radius.circular(15)),//圆角
                  borderSide: BorderSide(color: Colors.red, width: 2.0)),//颜色,宽度
            ),


颜色使用的是主题颜色,//TODO 这里设置的不生效,日后解决


表单 Form


在实际开发中,在请求接口之前会对输入框中的数据进行校验,如果对每个 TextField 都进行校验会非常麻烦,为此,Flutter 提供了一个 Form 组件,他可以对 输入框进行分组,然后统一进行一些操作,如内容校验,重置,保存等


Form 继承自 StatefulWidget 类,对应的状态为 FormState,定义如下:


Form({
  @required Widget child,
  bool autovalidate = false,
  WillPopCallback onWillPop,
  VoidCallback onChanged,
})


autovalidate:是否自动校验输入内容,当 为 true 时,每一个自 FormField 都会自动校验合法性,并直接显示错误信息。否则,需要通过 FormState.validate() 来手动校验

onWillPop:决定 Form 所在的路由是否可以直接返回(如点击返回按钮),该回调返回一个 Future 对象,若 Future 结果为 false,则当前路由不会返回,若为 true,则会返回到上一个路由,此属性通常用于拦截按钮

onChange:Form 的任意一个字 FormField 内容变化时都会触发此回调


FormField


Form 的子孙元素必须是 FormField 类型,FormField 是一个抽象类,有几个属性,FormState 通过他们来完成操作,FormField 部分定义如下:


const FormField({
  ...
  FormFieldSetter<T> onSaved, //保存回调
  FormFieldValidator<T>  validator, //验证回调
  T initialValue, //初始值
  bool autovalidate = false, //是否自动校验。
})


为了方便使用,Flutter 提供了一个 TextFormField 组件,他继承自 FormField 类,也是一个包装类,所以除了 FormField 之后,它还包括 TextField 的属性


FormState


FormState 为 Form 的 State 类,可以通过 Form.of() 或者 Globalkey 获得,我们可以通过他来对 Form 的子孙 FormField 进行统一的操作。


FormState.validate():此方法会调用 Form 子孙 FormFile 的1 validate 回调,如果有一个校验失败,则返回 false,所有校验失败的都会返回错误提示

FormState.save():此方法会调用 Form 子孙 FormField 的 save 回调,用于保存表单内容

FormSata.reset():调用此方法后,会将子孙 FormField 的内容清空


栗子


class InputText extends StatefulWidget {
  @override
  State<StatefulWidget> createState() {
    return _InputText();
  }
}
class _InputText extends State<InputText> {
  //定义一个controller
  TextEditingController _nameController = TextEditingController();
  GlobalKey _formKey = new GlobalKey<FormState>();
  @override
  void initState() {
    super.initState();
    _nameController.addListener(() => print("账号:" + _nameController.text));
  }
  @override
  Widget build(BuildContext context) {
    return Scaffold(
        appBar: AppBar(
          title: Text("输入框"),
        ),
        body: Padding(
          padding: const EdgeInsets.symmetric(vertical: 16, horizontal: 24),
          child: Form(
            key: _formKey,//设置globalKey,用于后面获取FormState
            autovalidate: true,//开启自动校验
            child: Column(
              children: [
                TextFormField(
                  autocorrect: true,
                  maxLength: 11,
                  controller: _nameController,
                  decoration: InputDecoration.collapsed(hintText: "用户名或邮箱"),
                  validator: (v) {
                    return v.trim().length > 0 ? null : "用户名不能为空";
                  },
                ),
                TextFormField(
                  decoration: InputDecoration.collapsed(hintText: "您的登录密码"),
                  validator: (v) {
                    return v.trim().length > 5 ? null : "密码不能少于6位";
                  },
                ),
                Padding(
                  padding: const EdgeInsets.only(top: 28),
                  child: Row(
                    children: [
                      Expanded(
                        child: RaisedButton(
                          padding: EdgeInsets.all(15),
                          child: Text("登录"),
                          color: Theme.of(context).primaryColor,
                          textColor: Colors.white,
                          onPressed: () {
                            //获取 formState ,调用 validate 验证合法性,
                            if ((_formKey.currentState as FormState)
                                .validate()) {
                              print('验证成功');
                            }
                          },
                        ),
                      )
                    ],
                  ),
                )
              ],
            ),
          ),
        ));
  }
}



在登录按钮的 onPressed 方法中不能通过 Form.of(context ) 来获取,原因是,此处的 context 为 InputText 的 context**,而 Form.of(context) 是根据所指定 context 向根去查找,而 FormState 是在 InputText 的子树中,所以不行。**


正确的做法是通过 Builder 来构建登录按钮,Builder 会将 widget 节点的 context 作为回调参数:


Expanded(
  child: Builder(builder: (context) {
    return RaisedButton(
      padding: EdgeInsets.all(15),
      child: Text("登录"),
      color: Theme.of(context).primaryColor,
      textColor: Colors.white,
      onPressed: () {
        //获取 formState ,调用 validate 验证合法性,
        if ((Form.of(context)).validate()) {
          print('验证成功');
        }
      },
    );
  }),
)


使用这种方式即可


相关文章
|
3月前
|
传感器 缓存 监控
Stream 组件在 Flutter 中的应用场景有哪些?
Stream 组件在 Flutter 中的应用场景有哪些?
187 58
|
3月前
|
UED 开发者
Flutter|常用数据通信组件
Flutter|常用数据通信组件
110 49
|
1月前
Flutter 自定义组件继承与调用的高级使用方式
本文深入探讨了 Flutter 中自定义组件的高级使用方式,包括创建基本自定义组件、继承现有组件、使用 Mixins 和组合模式等。通过这些方法,您可以构建灵活、可重用且易于维护的 UI 组件,从而提升开发效率和代码质量。
131 1
|
1月前
|
开发工具 UED
Flutter&鸿蒙next中封装一个输入框组件
本文介绍了如何创建一个简单的Flutter播客应用。首先,通过`flutter create`命令创建项目;接着,在`lib`目录下封装一个自定义输入框组件`CustomInput`;然后,在主应用文件`main.dart`中使用该输入框组件,实现简单的UI布局和功能;最后,通过`flutter run`启动应用。本文还提供了后续扩展建议,如状态管理、网络请求和UI优化。
107 1
|
3月前
|
开发工具
Flutter-AnimatedWidget组件源码解析
Flutter-AnimatedWidget组件源码解析
181 60
|
1月前
|
Dart UED
Flutter用户交互组件
Flutter用户交互组件
28 2
|
2月前
|
存储 开发框架 开发者
flutter:代码存储&基本组件 (五)
本文档介绍了Flutter中的一些基本组件和代码示例,包括代码存储、基本组件如AppBar的简单使用、可滑动切换的标签栏、TextField的多种用法(如简单使用、登录页面、文本控制器的监听与使用、修饰等),以及如何实现点击空白区域隐藏键盘等功能。通过这些示例,开发者可以快速掌握在Flutter应用中实现常见UI元素的方法。
|
1月前
|
开发工具
Flutter&鸿蒙next中封装一个列表组件
Flutter&鸿蒙next中封装一个列表组件
44 0
|
3月前
|
开发者
Flutter|常用数据通信组件
Flutter|常用数据通信组件
|
3月前
Stream 组件在 Flutter 中的具体使用方法是什么?
Stream 组件在 Flutter 中的具体使用方法是什么?
下一篇
DataWorks