Flutter TextField 自动匹配补全

Flutter中TextField本身并不支持自动匹配功能,因此需要我们自定义实现该功能。

首先考虑如何在TextField下方一个显示匹配选项的对话框,可以选择overlay实现该功能同时搭配CompositedTransformFollower是悬浮框跟随TextField,具体实现如下:

  var userName = TextEditingController();
  var passWord = TextEditingController();
  String inputTip = "";
  CommentFunction fuc = CommentFunction(); //调用公共函数
  OverlayEntry textFormOverlayEntry = new OverlayEntry(
    builder: (context) {
      return Container();
    },
  );
  bool overlayIsFirstVis = true; //账号匹配overlay是否第一次显示
  LayerLink layerLink = new LayerLink(); //overlay跟随

/**创建匹配选择悬浮框**/
 OverlayEntry createAccountOverly() {
    OverlayEntry overlayEntry = new OverlayEntry(builder: (context) {
      return new Positioned(
        width: 230,
        child: new CompositedTransformFollower(
          offset: Offset(5, 31),
          link: layerLink,
          child: new Material(
            child: new Container(
              constraints: BoxConstraints(maxHeight: 180),
              child: ListView.builder(
                shrinkWrap: true,
                itemCount: matchListData.length,
                itemBuilder: (context, index) {
                  return matchListData[index];
                },
              ),
            ),
          ),
        ),
      );
    });
    return overlayEntry;
  }

/**匹配选项**/
List<ListTile> matchListData = [];
  List getMatchData(String str) {
    List<String> list = [];
    int index = 0;
    for (int i = 0; i < str.length; ++i) {
      if (str[i] == '@') index = i;
    }
    String substr = str.substring(index);
    if (substr.length == str.length) {
      list = [
        "@163.com",
        "@126.com",
        "@qq.com",
        "@gmail.com",
        "@yeah.net",
        "@sina.com",
        "@139.com",
        "@188.cn",
      ];
      for (int i = 0; i < list.length; ++i) list[i] = str + list[i];
    } else if (substr.length == 1) {
      list = [
        "163.com",
        "126.com",
        "qq.com",
        "gmail.com",
        "yeah.net",
        "sina.com",
        "139.com",
        "189.cn",
      ];
      for (int i = 0; i < list.length; ++i) list[i] = str + list[i];
    } else if (substr.length > 1) {
      List tempList = [
        "@163.com",
        "@126.com",
        "@qq.com",
        "@gmail.com",
        "@yeah.net",
        "@sina.com",
        "@139.com",
        "@189.cn",
      ];
      list.clear();
      for (int i = 0; i < tempList.length; ++i) {
        if (isChildStr(substr, tempList[i])) {
          list.add(tempList[i]);
        }
      }
      String preStr = str.substring(0, index);
      for (int i = 0; i < list.length; ++i) list[i] = preStr + list[i];
    }
    matchListData.clear();
    for (int i = 0; i < list.length; ++i) {
      matchListData.add(ListTile(
        dense: true,
        hoverColor: Colors.black12,
        title: Text(list[i]),
        onTap: () {
          userName.text = list[i];
          textFormOverlayEntry.remove();
          overlayIsFirstVis = true;
        },
      ));
    }
    return matchListData;
  }

 bool isChildStr(String str1, String str2) {
    for (int i = 1; i < str1.length; ++i) {
      if (str1[i] != str2[i]) return false;
    }
    return true;
  }
/**输入框 */
  Widget inputAccountContainer() {
    return Container(
      height: 30,
      width: 240,
      child: TextField(
          controller: userName,
          textAlign: TextAlign.justify,
          cursorColor: Colors.black38,
          obscureText: false,
          cursorWidth: 1,
          decoration: InputDecoration(
            hintText: "163/QQ/Gmail/等",
            contentPadding: const EdgeInsets.only(
                top: 8.0, left: 2, right: -15.0, bottom: 0),
            border: OutlineInputBorder(
                borderRadius: BorderRadius.circular(0),
                borderSide: BorderSide(color: Colors.black26, width: 0)),
            enabledBorder: OutlineInputBorder(
              //选中时边框颜色
              borderRadius: BorderRadius.circular(0),
              borderSide: BorderSide(color: Colors.black26),
            ),
            focusedBorder: OutlineInputBorder(
              //失焦时边框颜色
              borderRadius: BorderRadius.circular(0),
              borderSide: BorderSide(color: Colors.black26),
            ),
          ),
          onChanged: (value) {
            matchAccounntState();
          }),
    );
  }

 /**账号匹配 */
  void matchAccounntState() {
    inputTip = "";
    getMatchData(userName.text);
    if (userName.text.length != 0) {
      if (overlayIsFirstVis) {
        textFormOverlayEntry = createAccountOverly();
        overlayIsFirstVis = false;
        Overlay.of(context)?.insert(textFormOverlayEntry);
      } else {
        textFormOverlayEntry.remove();
        textFormOverlayEntry = createAccountOverly();
        Overlay.of(context)?.insert(textFormOverlayEntry);
      }
    } else {
      textFormOverlayEntry.remove();
      overlayIsFirstVis = true;
    }
    setState(() {});
  }

最终的实现效果:

Flutter TextField 自动匹配补全Flutter TextField 自动匹配补全

Flutter TextField 自动匹配补全

上一篇:better-scroll插件


下一篇:swiftUI设置TextField的placeholder自定义文本颜色