一、前言

flutter开发中,有时候的页面例如OA流程、贷款申请等等一系列的流程操作,必不可少的就是填写表单,在flutter中,表单会有很多种,例如“text”文本框,”options“下拉框、”select“选择框等等。为了减少冗余代码开发,各项目组公司会封装一套自己的自定义表单组件提供使用。但往往随着需求的更新、变化,当年公司封装的一套表单有时候并不能满足自己的实际需求。因此,个人也结合网上看到的内容,自己写一个简单的表单,目的是将表单中的一二级联动进行抽离(公司中封装的组件表单在联动一块稍有些瑕疵,影响功能),方便表单联动使用。表单的style仿照公司需要的表单style,具体UI如下:

在这里插入图片描述

二、代码层

import 'package:flutter/material.dart';
import 'package:flutter/services.dart';


typedef GestureTapCallback = void Function();

class ContentView extends StatelessWidget {
  // 标题
  final String title;

  //是否必填的标志
  final String mustType;

  //输入框 显示的灰色提示文字
  final String hintText;

  final TextEditingController controller;

  //下拉框数组
  final List contentList;

  // 输入框是否只读 默认 false
  final bool readOnly;

  //文字显示的位置
  final TextAlign textAlign;

  //输入框键盘样式
  final TextInputType keyboardType;

  //输入框右边👉显示的widget
  /*
  *suffixIcon: Container(
                width: 40,
                height: 40,
                child: Icon(Icons.format_list_bulleted),
                alignment: Alignment.centerRight,
              ),
  */
  final Widget suffixIcon;

  //判断 类型 是 输入 还是 下拉选择
  final bool style;

  // 下拉框点击事件
  final ValueChanged<String> onChanged;

  // 输入框输入的类型限制,只能输入数字、汉字等
  final List<TextInputFormatter> inputFormatters;

  // 输入框不可输入时的点击事件
  final GestureTapCallback onTap;
  //光标焦点
  final FocusNode focusNode;

  //输入框左边title的宽度
  final num titleWidth;

  ContentView({
    this.title = '',
    this.mustType = '',
    this.hintText = '',
    this.controller,
    this.contentList,
    this.readOnly = false,
    this.textAlign,
    this.keyboardType,
    this.suffixIcon,
    this.style = false,
    this.onChanged,
    this.inputFormatters,
    this.onTap,
    this.focusNode,
    this.titleWidth,
  });

  factory ContentView.textfield({
    String title = '',
    String mustType = '',
    String hintText = '',
    @required TextEditingController controller,
    //是否只读
    bool readOnly = false,
    //光标开始位置
    TextAlign textAlign = TextAlign.right,
    TextInputType keyboardType,
    Widget suffixIcon,
    ValueChanged<String> onChanged,
    List<TextInputFormatter> inputFormatters,
    GestureTapCallback onTap,
    FocusNode focusNode,
    num titleWidth,
  }) {
    return ContentView(
      controller: controller,
      title: title,
      mustType: mustType,
      hintText: hintText,
      readOnly: readOnly,
      textAlign: textAlign,
      keyboardType: keyboardType,
      suffixIcon: suffixIcon,
      style: false,
      onChanged: onChanged,
      inputFormatters: inputFormatters,
      onTap: onTap,
      focusNode: focusNode,
      titleWidth: titleWidth,
    );
  }

  factory ContentView.dropdownView({
    String title = '',
    String mustType = '',
    String hintText = '',
    @required TextEditingController controller,
    @required List contentList,
    TextAlign textAlign = TextAlign.right,
    ValueChanged<String> onChanged,
    num titleWidth,
  }) {
    return ContentView(
      controller: controller,
      title: title,
      mustType: mustType,
      hintText: hintText,
      contentList: contentList,
      textAlign: textAlign,
      style: true,
      onChanged: onChanged,
      titleWidth: titleWidth,
    );
  }

  @override
  Widget build(BuildContext context) {
    return Column(
      children: <Widget>[
        Container(
          color: Colors.white,
          child: ListTile(
            title: Row(
              children: <Widget>[
                Text(
                  mustType,
                  style: TextStyle(color: Colors.red),
                ),
                Text(
                  title,
                  style: TextStyle(fontSize: 16),
                ),
              ],
            ),
            trailing: Container(
              padding: EdgeInsets.fromLTRB(0, 0, 20, 0),
              child: this.style == false
                  ? TextField(
                      keyboardType: this.keyboardType,
                      readOnly: this.readOnly,
                      controller: controller,
                      textAlign: this.textAlign,
                      onChanged: this.onChanged,
                      inputFormatters: this.inputFormatters,
                      onTap: this.onTap,
                      focusNode: focusNode,
                      decoration: InputDecoration(
                        border: InputBorder.none,
                        hintText: hintText,
                        hintStyle: TextStyle(fontSize: 16),
                        suffixIcon: this.suffixIcon,
                      ),
                    )
                  : DropdownButtonFormField(
                      decoration: InputDecoration(
                        border: InputBorder.none,
                        hintText: hintText,
                        hintStyle: TextStyle(fontSize: 16),
                        contentPadding: EdgeInsets.fromLTRB(0, 0, 0, 0),
                      ),
                      value: controller.text == '' ? null : controller.text,
                      items: contentList
                          .map((title) => DropdownMenuItem(
                                child: Center(
                                  child: Text(title),
                                ),
                                value: title,
                              ))
                          .toList(),
                      onChanged: (title) {
//                        setState(() {
                          controller.text = title;
                          this.onChanged(title);
//                        });

                      }),
              width: MediaQuery.of(context).size.width -
                  (this.titleWidth == null ? 136 : this.titleWidth),
            ),
          ),
        ),
        Divider(
          height: 1,
        ),
      ],
    );
  }
}

若当前ui页面有用到的同学,可以私信我一起交流下数据交互问题,暂时就不写下来了

Logo

华为开发者空间,是为全球开发者打造的专属开发空间,汇聚了华为优质开发资源及工具,致力于让每一位开发者拥有一台云主机,基于华为根生态开发、创新。

更多推荐