flutter聊天界面-TextField输入框实现@功能等匹配正则表达式展示高亮功能

flutter聊天界面-聊天列表 下拉加载更多历史消息 flutter聊天界面-聊天列表 下拉加载更多历史消息,主要实现Column中使用Expand嵌套ListView布局,设置reverse、physics、ScrollBehavior。可以解决reverse为true首导致顶部大片空白问题,去除ListView滑动波纹。之后在消息的最后一条设置为加载更多消息指示器与没有更多消息提示。 阅读详情

flutter聊天界面-TextField输入框实现@功能等匹配正则表达式展示高亮功能

一、简要描述

描述:
最近有位朋友讨论的时候,提到了输入框的高亮展示。在flutter TextField中需要插入特殊样式的标签,比如:“请 @张三 回答一下”,这一串字符在TextField中输入,当输入@时 弹出好友列表选择,然后将 “@张三”高亮显示在TextField中。

效果图如下

在这里插入图片描述
视频效果

flutter聊天界面-TextField输入框实现@功能

昨天整理的文中,简单实用TextEditingController的buildTextSpan时候,直接修改代码

List<InlineSpan> textSpans = RichTextHelper.getRichText(value.text);
    if (composingRegionOutOfRange) {
      return TextSpan(style: style, children: textSpans);
    }

会出现光标输入的问题,这里修改了一下,完善了一下。

大家可以使用rich_text_controller来实现,查看rich_text_controller源码可以看到,RichTextController继承TextEditingController,重写了buildTextSpan。经过我在iPhone上测试,当输入@汉字的时候,对中文兼容会有问题,这里做一下修改完善修改。

二、TextEditingController的buildTextSpan方法

在TextEditingController中buildTextSpan方法中,我们可以看到,该方法中的代码
在这里插入图片描述

composingRegionOutOfRange:仅有输入完成的字

在最后一部分的代码中含有未输入完成的字

final TextStyle composingStyle = style?.merge(const TextStyle(decoration: TextDecoration.underline))
        ?? const TextStyle(decoration: TextDecoration.underline);
    return TextSpan(
      style: style,
      children: <TextSpan>[
        TextSpan(text: value.composing.textBefore(value.text)),
        TextSpan(
          style: composingStyle,
          text: value.composing.textInside(value.text),
        ),
        TextSpan(text: value.composing.textAfter(value.text)),
      ],
    );
  • composingStyle未输入完成的字的样式,可以自己做下修改。

  • value.composing.textBefore:当前输入前面的字。

  • value.composing.textAfter:当前输入后面的字。

当输入过程中,我们将value.composing.textBefore,value.composing.textAfter匹配高亮即可

代码如下

value.composing.textBefore

TextSpan(style: style, children: buildRegExpSpan(context: context, text: value.composing.textBefore(value.text))),

value.composing.textAfter

TextSpan(style: style, children: buildRegExpSpan(context: context, text: value.composing.textAfter(value.text))),

匹配正则表达式

List<TextSpan> buildRegExpSpan(
      {required BuildContext context,
        TextStyle? style,
        required String? text}) {
    List<TextSpan> children = [];
    if (!(text != null && text.isNotEmpty)) {
      return children;
    }
    final matches = <String>{};
    List<Map<String, List<int>>> matchIndex = [];

    // Validating with REGEX
    RegExp? allRegex;
    allRegex = patternMatchMap != null
        ? RegExp(patternMatchMap?.keys.map((e) => e.pattern).join('|') ?? "",
        caseSensitive: regExpCaseSensitive,
        dotAll: regExpDotAll,
        multiLine: regExpMultiLine,
        unicode: regExpUnicode)
        : null;
    // Validating with Strings
    RegExp? stringRegex;
    stringRegex = stringMatchMap != null
        ? RegExp(r'\b' + stringMatchMap!.keys.join('|').toString() + r'+\$',
        caseSensitive: regExpCaseSensitive,
        dotAll: regExpDotAll,
        multiLine: regExpMultiLine,
        unicode: regExpUnicode)
        : null;
    ////
    text.splitMapJoin(
      stringMatchMap == null ? allRegex! : stringRegex!,
      onNonMatch: (String span) {
        if (stringMatchMap != null &&
            children.isNotEmpty &&
            stringMatchMap!.keys.contains("${children.last.text}$span")) {
          final String? ks =
          stringMatchMap!["${children.last.text}$span"] != null
              ? stringMatchMap?.entries.lastWhere((element) {
            return element.key
                .allMatches("${children.last.text}$span")
                .isNotEmpty;
          }).key
              : '';

          children.add(TextSpan(text: span, style: stringMatchMap![ks!]));
          return span.toString();
        } else {
          children.add(TextSpan(text: span, style: style));
          return span.toString();
        }
      },
      onMatch: (Match m) {
        matches.add(m[0]!);
        final RegExp? k = patternMatchMap?.entries.firstWhere((element) {
          return element.key.allMatches(m[0]!).isNotEmpty;
        }).key;

        final String? ks = stringMatchMap?[m[0]] != null
            ? stringMatchMap?.entries.firstWhere((element) {
          return element.key.allMatches(m[0]!).isNotEmpty;
        }).key
            : '';
        if (deleteOnBack!) {
          if ((isBack(text!, _lastValue) && m.end == selection.baseOffset)) {
            WidgetsBinding.instance.addPostFrameCallback((_) {
              children.removeWhere((element) => element.text! == text);
              text = text!.replaceRange(m.start, m.end, "");
              selection = selection.copyWith(
                baseOffset: m.end - (m.end - m.start),
                extentOffset: m.end - (m.end - m.start),
              );
            });
          } else {
            children.add(
              TextSpan(
                text: m[0],
                style: stringMatchMap == null
                    ? patternMatchMap![k]
                    : stringMatchMap![ks],
              ),
            );
          }
        } else {
          children.add(
            TextSpan(
              text: m[0],
              style: stringMatchMap == null
                  ? patternMatchMap![k]
                  : stringMatchMap![ks],
            ),
          );
        }
        final resultMatchIndex = matchValueIndex(m);
        if (resultMatchIndex != null && onMatchIndex != null) {
          matchIndex.add(resultMatchIndex);
          onMatchIndex!(matchIndex);
        }

        return (onMatch(List<String>.unmodifiable(matches)) ?? '');
      },
    );
    return children;
  }

这里使用的是rich_text_controller中的代码,做了相应的修改,输入@张三正则表达式正常高亮显示了。

整个text_field_controller代码如下

import 'package:flutter/material.dart';

class TextFieldController extends TextEditingController {
  final Map<RegExp, TextStyle>? patternMatchMap;
  final Map<String, TextStyle>? stringMatchMap;
  final Function(List<String> match) onMatch;
  final Function(List<Map<String, List<int>>>)? onMatchIndex;
  final bool? deleteOnBack;
  String _lastValue = "";

  /// controls the caseSensitive property of the full [RegExp] used to pattern match
  final bool regExpCaseSensitive;

  /// controls the dotAll property of the full [RegExp] used to pattern match
  final bool regExpDotAll;

  /// controls the multiLine property of the full [RegExp] used to pattern match
  final bool regExpMultiLine;

  /// controls the unicode property of the full [RegExp] used to pattern match
  final bool regExpUnicode;

  bool isBack(String current, String last) {
    return current.length < last.length;
  }

  TextFieldController(
      {String? text,
        this.patternMatchMap,
        this.stringMatchMap,
        required this.onMatch,
        this.onMatchIndex,
        this.deleteOnBack = false,
        this.regExpCaseSensitive = true,
        this.regExpDotAll = false,
        this.regExpMultiLine = false,
        this.regExpUnicode = false})
      : assert((patternMatchMap != null && stringMatchMap == null) ||
      (patternMatchMap == null && stringMatchMap != null)),
        super(text: text);

  /// Setting this will notify all the listeners of this [TextEditingController]
  /// that they need to update (it calls [notifyListeners]).
  
  set text(String newText) {
    value = value.copyWith(
      text: newText,
      selection: const TextSelection.collapsed(offset: -1),
      composing: TextRange.empty,
    );
  }

  /// Builds [TextSpan] from current editing value.
  
  TextSpan buildTextSpan(
      {required BuildContext context,
        TextStyle? style,
        required bool withComposing}) {
    assert(!value.composing.isValid || !withComposing || value.isComposingRangeValid);
    // If the composing range is out of range for the current text, ignore it to
    // preserve the tree integrity, otherwise in release mode a RangeError will
    // be thrown and this EditableText will be built with a broken subtree.
    final bool composingRegionOutOfRange = !value.isComposingRangeValid || !withComposing;

    if (composingRegionOutOfRange) {
      List<TextSpan> children = [];
      final matches = <String>{};
      List<Map<String, List<int>>> matchIndex = [];

      // Validating with REGEX
      RegExp? allRegex;
      allRegex = patternMatchMap != null
          ? RegExp(patternMatchMap?.keys.map((e) => e.pattern).join('|') ?? "",
          caseSensitive: regExpCaseSensitive,
          dotAll: regExpDotAll,
          multiLine: regExpMultiLine,
          unicode: regExpUnicode)
          : null;
      // Validating with Strings
      RegExp? stringRegex;
      stringRegex = stringMatchMap != null
          ? RegExp(r'\b' + stringMatchMap!.keys.join('|').toString() + r'+\$',
          caseSensitive: regExpCaseSensitive,
          dotAll: regExpDotAll,
          multiLine: regExpMultiLine,
          unicode: regExpUnicode)
          : null;
      ////
      text.splitMapJoin(
        stringMatchMap == null ? allRegex! : stringRegex!,
        onNonMatch: (String span) {
          if (stringMatchMap != null &&
              children.isNotEmpty &&
              stringMatchMap!.keys.contains("${children.last.text}$span")) {
            final String? ks =
            stringMatchMap!["${children.last.text}$span"] != null
                ? stringMatchMap?.entries.lastWhere((element) {
              return element.key
                  .allMatches("${children.last.text}$span")
                  .isNotEmpty;
            }).key
                : '';

            children.add(TextSpan(text: span, style: stringMatchMap![ks!]));
            return span.toString();
          } else {
            children.add(TextSpan(text: span, style: style));
            return span.toString();
          }
        },
        onMatch: (Match m) {
          matches.add(m[0]!);
          final RegExp? k = patternMatchMap?.entries.firstWhere((element) {
            return element.key.allMatches(m[0]!).isNotEmpty;
          }).key;

          final String? ks = stringMatchMap?[m[0]] != null
              ? stringMatchMap?.entries.firstWhere((element) {
            return element.key.allMatches(m[0]!).isNotEmpty;
          }).key
              : '';
          if (deleteOnBack!) {
            if ((isBack(text, _lastValue) && m.end == selection.baseOffset)) {
              WidgetsBinding.instance.addPostFrameCallback((_) {
                children.removeWhere((element) => element.text! == text);
                text = text.replaceRange(m.start, m.end, "");
                selection = selection.copyWith(
                  baseOffset: m.end - (m.end - m.start),
                  extentOffset: m.end - (m.end - m.start),
                );
              });
            } else {
              children.add(
                TextSpan(
                  text: m[0],
                  style: stringMatchMap == null
                      ? patternMatchMap![k]
                      : stringMatchMap![ks],
                ),
              );
            }
          } else {
            children.add(
              TextSpan(
                text: m[0],
                style: stringMatchMap == null
                    ? patternMatchMap![k]
                    : stringMatchMap![ks],
              ),
            );
          }
          final resultMatchIndex = matchValueIndex(m);
          if (resultMatchIndex != null && onMatchIndex != null) {
            matchIndex.add(resultMatchIndex);
            onMatchIndex!(matchIndex);
          }

          return (onMatch(List<String>.unmodifiable(matches)) ?? '');
        },
      );

      _lastValue = text;
      return TextSpan(style: style, children: children);
    }

    final TextStyle composingStyle = style?.merge(const TextStyle(decoration: TextDecoration.underline))
        ?? const TextStyle(decoration: TextDecoration.underline);
    return TextSpan(
      children: <TextSpan>[
        TextSpan(style: style, children: buildRegExpSpan(context: context, text: value.composing.textBefore(value.text))),
        TextSpan(
          style: composingStyle,
          text: value.composing.textInside(value.text),
        ),
        TextSpan(style: style, children: buildRegExpSpan(context: context, text: value.composing.textAfter(value.text))),
      ],
    );
  }

  Map<String, List<int>>? matchValueIndex(Match match) {
    final matchValue = match[0]?.replaceFirstMapped('#', (match) => '');
    if (matchValue != null) {
      final firstMatchChar = match.start + 1;
      final lastMatchChar = match.end - 1;
      final compactMatch = {
        matchValue: [firstMatchChar, lastMatchChar]
      };
      return compactMatch;
    }
    return null;
  }

  List<TextSpan> buildRegExpSpan(
      {required BuildContext context,
        TextStyle? style,
        required String? text}) {
    List<TextSpan> children = [];
    if (!(text != null && text.isNotEmpty)) {
      return children;
    }
    final matches = <String>{};
    List<Map<String, List<int>>> matchIndex = [];

    // Validating with REGEX
    RegExp? allRegex;
    allRegex = patternMatchMap != null
        ? RegExp(patternMatchMap?.keys.map((e) => e.pattern).join('|') ?? "",
        caseSensitive: regExpCaseSensitive,
        dotAll: regExpDotAll,
        multiLine: regExpMultiLine,
        unicode: regExpUnicode)
        : null;
    // Validating with Strings
    RegExp? stringRegex;
    stringRegex = stringMatchMap != null
        ? RegExp(r'\b' + stringMatchMap!.keys.join('|').toString() + r'+\$',
        caseSensitive: regExpCaseSensitive,
        dotAll: regExpDotAll,
        multiLine: regExpMultiLine,
        unicode: regExpUnicode)
        : null;
    ////
    text.splitMapJoin(
      stringMatchMap == null ? allRegex! : stringRegex!,
      onNonMatch: (String span) {
        if (stringMatchMap != null &&
            children.isNotEmpty &&
            stringMatchMap!.keys.contains("${children.last.text}$span")) {
          final String? ks =
          stringMatchMap!["${children.last.text}$span"] != null
              ? stringMatchMap?.entries.lastWhere((element) {
            return element.key
                .allMatches("${children.last.text}$span")
                .isNotEmpty;
          }).key
              : '';

          children.add(TextSpan(text: span, style: stringMatchMap![ks!]));
          return span.toString();
        } else {
          children.add(TextSpan(text: span, style: style));
          return span.toString();
        }
      },
      onMatch: (Match m) {
        matches.add(m[0]!);
        final RegExp? k = patternMatchMap?.entries.firstWhere((element) {
          return element.key.allMatches(m[0]!).isNotEmpty;
        }).key;

        final String? ks = stringMatchMap?[m[0]] != null
            ? stringMatchMap?.entries.firstWhere((element) {
          return element.key.allMatches(m[0]!).isNotEmpty;
        }).key
            : '';
        if (deleteOnBack!) {
          if ((isBack(text!, _lastValue) && m.end == selection.baseOffset)) {
            WidgetsBinding.instance.addPostFrameCallback((_) {
              children.removeWhere((element) => element.text! == text);
              text = text!.replaceRange(m.start, m.end, "");
              selection = selection.copyWith(
                baseOffset: m.end - (m.end - m.start),
                extentOffset: m.end - (m.end - m.start),
              );
            });
          } else {
            children.add(
              TextSpan(
                text: m[0],
                style: stringMatchMap == null
                    ? patternMatchMap![k]
                    : stringMatchMap![ks],
              ),
            );
          }
        } else {
          children.add(
            TextSpan(
              text: m[0],
              style: stringMatchMap == null
                  ? patternMatchMap![k]
                  : stringMatchMap![ks],
            ),
          );
        }
        final resultMatchIndex = matchValueIndex(m);
        if (resultMatchIndex != null && onMatchIndex != null) {
          matchIndex.add(resultMatchIndex);
          onMatchIndex!(matchIndex);
        }

        return (onMatch(List<String>.unmodifiable(matches)) ?? '');
      },
    );
    return children;
  }
}

至此可以看到效果图中@张三 高亮显示了。

三、使用TextFieldController测试@张三 高亮

调整好TextFieldController后,我这里测试@张三 高亮

我们进行初始化TextFieldController

// Add a controller
  late TextFieldController _controller;

  
  void initState() {
    // TODO: implement initState
    _controller = TextFieldController(
      patternMatchMap: {
        //
        //* Returns every Hashtag with red color
        //
        RegExp(r"@[^\s]+\s?"):TextStyle(color:Colors.green),
        //
        //* Returns every Hashtag with red color
        //
        RegExp(r"\B#[a-zA-Z0-9]+\b"):TextStyle(color:Colors.red),
        //
        //* Returns every Mention with blue color and bold style.
        //
        RegExp(r"\B@[a-zA-Z0-9]+\b"):TextStyle(fontWeight: FontWeight.w800 ,color:Colors.blue,),
        //
        //* Returns every word after '!' with yellow color and italic style.
        //
        RegExp(r"\B![a-zA-Z0-9]+\b"):TextStyle(color:Colors.yellow, fontStyle:FontStyle.italic),
        // add as many expressions as you need!
      },
      //* starting v1.2.0
      // Now you have the option to add string Matching!
      // stringMatchMap: {
      //   "String1":TextStyle(color: Colors.red),
      //   "String2":TextStyle(color: Colors.yellow),
      // },
      //! Assertion: Only one of the two matching options can be given at a time!

      //* starting v1.1.0
      //* Now you have an onMatch callback that gives you access to a List<String>
      //* which contains all matched strings
      onMatch: (List<String> matches){
        // Do something with matches.
        //! P.S
        // as long as you're typing, the controller will keep updating the list.
      },
      deleteOnBack: true,
      // You can control the [RegExp] options used:
      regExpUnicode: true,
    );

    super.initState();
  }

在TextField中使用TextFieldController。具体代码如下

TextField(
        minLines: 1,
        maxLines: null,
        keyboardType: TextInputType.multiline,
        textAlignVertical: TextAlignVertical.center,
        autofocus: true,
        focusNode: editFocusNode,
        controller: _controller,
        textInputAction: TextInputAction.send,
        decoration: InputDecoration(
          contentPadding: EdgeInsets.symmetric(vertical: 10, horizontal: 8.0),
          filled: true,
          isCollapsed: true,
          floatingLabelBehavior: FloatingLabelBehavior.never,
          hintText: "说点什么吧~",
          hintStyle: TextStyle(
            fontSize: 14,
            fontWeight: FontWeight.w400,
            fontStyle: FontStyle.normal,
            color: ColorUtil.hexColor(0xACACAC),
            decoration: TextDecoration.none,
          ),
          enabledBorder: OutlineInputBorder(
            /*边角*/
            borderRadius: const BorderRadius.all(
              Radius.circular(5.0), //边角为30
            ),
            borderSide: BorderSide(
              color: ColorUtil.hexColor(0xf7f7f7), //边框颜色为绿色
              width: 1, //边线宽度为1
            ),
          ),
          focusedBorder: OutlineInputBorder(
            borderRadius: const BorderRadius.all(
              Radius.circular(5.0), //边角为30
            ),
            borderSide: BorderSide(
              color: ColorUtil.hexColor(0xECECEC), //边框颜色为绿色
              width: 1, //宽度为1
            ),
          ),
        ),
      )

经过输入删除测试,输入的“@张三”高亮显示在TextField中正常了。

使用TextEditingController的buildTextSpan,可以查看:https://blog.youkuaiyun.com/gloryFlow/article/details/132889374
完善TextField输入框匹配正则表达式高亮显示,可以查看:https://blog.youkuaiyun.com/gloryFlow/article/details/132899084

四、小结

flutter聊天界面-TextField输入框buildTextSpan实现@功能展示高亮功能。自定义修改TextEditingController。
内容较多,描述可能不准确,请见谅。

本文地址:https://blog.youkuaiyun.com/gloryFlow/article/details/132899084

学习记录,每天不停进步。

Flutter GetX 实现 ChatGPT 简单聊天界面 Flutter 是一款跨平台的移动应用开发框架,而 GetX 是 Flutter 中一种简单易用的状态管理和路由管理工具。本篇我们将使用 Flutter 和 GetX 实现一个简单的聊天界面,以与 ChatGPT 进行交互。 阅读详情

相关推荐

江科大笔记—OLED调试工具

OLED介绍及调试工具

m0_62005595的博客 658

flutter聊天界面-TextField输入框buildTextSpan实现@功能展示高亮功能

flutter聊天界面-TextField输入框buildTextSpan实现@功能展示高亮功能最近有位朋友讨论的时候,提到了输入框的高亮展示。在flutter TextField中需要插入特殊样式的标签,比如:“请 @张三 回答一下”,这一串字符在TextField中输入,当输入@时 弹出好友列表选择,然后将 “@张三”高亮显示在TextField中。效果图如下。

一名开发者 2540

FlinkCDC数据同步Bug——同步性能由于写入并行度限制无法提升问题的解决

使用FlinkCDC进行数据同步时,出现增量阶段写入并行度强制为1导致整体同步性能无法提升问题的解决方案

csdn_lan的博客 2080

Flutter iOS输入法 Bug Fix 记录

前言 该文章只记录与工作中碰到的问题,Flutter 版本为 1.2.6 。有更多解决办法欢迎讨论学习。 背景 产品想要在商品搜索界面实现实时搜索。用户在输入商品名称的时候 就自动搜索商品信息。 问题 ios机型在原生键盘中文场景下,在输入字母拼音时onChanged:方法在iOS上会实时回调,拼音也会被搜索。如果输入过快,由于接口异步回调导致内容展示异常。 错误解决办法 输入中文时限制字母拼音在输入框内的显示,待选择中文后再显示,此时回调onChanged(不推荐使用,商品并非都是中文) 使用dart自

魔都大白 1342

windchill安装搭建(保姆式)

保姆式搭建windchill 材料准备 Vmware工具,用来创建和打开虚拟机的工具 安装系统的镜像文件 数据库安装文件,这里是Oracle数据库 Windchill的安装包 Vmware工具,用来安装和打开虚拟机的软件 Windowsserver2008的镜像工具,用来安装虚拟机环境的系统,如果你有win2007或win2010的也可以,在做虚拟机时,需要先安装系统。 Oracle数据库安装包 Windchill11M030的安装包 (安装包如有需要可以私信邮箱发送) 虚拟机安装 安装虚拟机VMware

tr1294937662的博客 6217

台达伺服B3驱动器参数的设定和CN1的接法

3. B2的电子齿轮比是直接设定P1-44(分子)和P1-45(分母)就就可以的,但是B3的有个隐藏的细节,就是P1-44的默认值77216不用去更改,这是官方客服说的,需要改的是P1-45这个参数,比如说,我使用的丝杆螺距是5mm的,那么就是以5000脉冲走完5mm为一圈,则就把P1-45设定为5000即可;我的是三菱FX3S系列的PLC,是NPN型的,输出点是24V-作为信号的,所以接41、37,具体可参考B3的。,跟着客服的讲解操作才解决的,以下就是解决方法,希望能够帮到需要的各位。

qq_38681017的博客 1万+

Flutter 正则表达式控制TextField输入框内容

Flutter 正则表达式控制TextField输入框内容 1、添加InputFormatter类继承TextInputFormatter,更加输入根据正则表达式进行匹配,匹配成功返回新的内容,不成功就不让输入 class InputFormatter extends TextInputFormatter { final String regExp; InputFormatter(this.regExp); @override TextEditingValue formatEditUpdat

muzihaoi的博客 2765

车载导航测试,面试常见问题

车载导航测试是汽车软件测试的重要组成部分,涉及验证导航系统的功能、性能、可靠性和用户体验。在面试中,面试官通常会考察候选人的测试思维、问题解决能力和实际经验。以下我将从常见问题类别入手,逐步介绍面试中的高频问题,并提供结构化分析。通过以上结构化准备,你能在面试中自信应对车载导航测试相关问题。用户体验测试关注界面友好性和交互流畅性,安全测试则涉及功能安全和数据隐私。功能测试聚焦于导航核心功能的正确性,如路线规划、位置定位和地图显示。面试官会考察你如何识别、报告和跟踪缺陷,以及熟悉测试工具。

m0_69889939的博客 527

flutter 自适应宽高气泡框,聊天气泡框

还有的就是通过算child 然后动态计算气泡框宽高,脱裤子💨,放到listview 刷新数据还会丢ui,因为要算某一个widget 的大小,必须是已经加载过,然后你再刷新listview然后更新大小。不管是text内容,还是布局大小你要计算那就GG。Container 红色正方形 然后 你剪切绘制成 气泡框的样子,然后 夹角长, 你直接Container padding 个夹角长度 ,内容不就显示全了么?看看我发表时间,我真的潦草一下博客吧。网上好多气泡框,都让写固定宽高,无法自适应文本内容。

qq_35629609的博客 1177

华为OD机试真题 新系统2026-04-01 Java&Go【计算数列位置N的值】

如果其前面的M个元素中,存在值相同的元素,则该位置上的数值等于前面M个数中最大的数值与最小的数值之如果其前面的M个元素中,不存在值相同的元素,则该位置上的数值等于前面M个数中最大的数值与最小的数值之差;1、输入M、N两个数,则按照以下规则形成一个数列;两个整数,用逗号分割,分别表示M和N。一个整数,表示数列第N个位置上的数值。2、数列的前M个元素的值为1到M;请计算该数列第N个位置上的数值。N取值范围:1<= N<=50。M取值范围:3<=M<=10。

MISAYAONE的博客 2049

华为嵌入式面试题及参考答案(持续更新)

异步是指在程序执行过程中,某些任务不需要等待立即完成就可以继续执行其他任务的过程。在计算机编程中,异步通常用于处理长时间运行的操作,如文件读写、网络通信等,以避免阻塞主线程。异步处理通常涉及到回调函数、事件循环、协程或未来的概念。使用宏定义来避免命名冲突。#else#endif堆和栈是计算机程序中用于存储数据的两种不同类型的内存区域。

大模型大数据攻城狮的专栏 2484

移动端集成OpenAI Codex:架构设计与工程实践指南

代码生成与智能补全是现代软件开发中的关键技术,其核心原理基于大规模语言模型对编程语言模式和上下文逻辑的深度理解。通过分析海量代码库,模型能够学习语法结构、API使用模式和最佳实践,从而在开发者编写代码时提供精准建议。这项技术的工程价值在于显著提升开发效率、降低编码错误率,并辅助学习新语言或框架。在应用场景上,除了常见的桌面IDE插件,移动端集成正成为新兴方向,尤其适合编程学习、代码审查和轻量级开发辅助等场景。针对移动端特有的网络不稳定、屏幕尺寸有限等挑战,需要采用代理服务架构确保API密钥安全,并通过流式响

weixin_30363509的博客 399

从苏宁电器到卡巴斯基(第二部)第01篇:我在卡巴的日子 I

聊聊行业薪酬 我相信不论是谁,如果是入职一家新的公司,那么他最想知道的一件事情就是待遇情况了。这里既包含每月实际能到手多少钱,又包括五险一金是否齐全以及是按照高标准还是低标准缴纳。另外,如果是入职IT公司,还会在意年终奖有多少,毕竟某些富裕的IT企业,每到年末就会以此制造新闻来博取大家的关注,以彰显自身的实力。 一言以蔽之,待遇问题也就是年收入究竟会有多少,也是我们进入职场的人喜欢相互打听的问题。比如我研究生那届最厉害的一位同学,签了A公司的算法岗位,年薪30W+(税前,下同),在当时的我看来就是天价了

Gleam的专栏 1225

flutter 微信聊天输入框

高仿微信聊天输入框,效果图如下(目前都是静态展示,服务还没开始开发):大家如果观察仔细的话 应该会发现,;所以在这里就需要监听软键盘的高度 ()(第二张动图 是github上的不知道能放多久)遇到有个问题就是:这里这只,就能自适应高度了。就能做到TextField多行输入了代码结构如下:------ chat_bottom.dart 聊天底部输入框------ chat_element_other.dart 聊天时别人信息的显示。

唐僧的专栏 1万+

Statistics and Machine Learning Toolbox

Statistics and Machine Learning Toolbox(带书签),MATLAB统计学习工具

jdk-8u144-linux-x64.tar.gz.

该资源为搭建Linux系统Java环境用,资源的后缀为tar.gz格式的压缩包

flutter的TextField参数、案例整理(上)

通过点击button控制键盘显隐、TextField参数简解

无趣的博客 826

VC中sqlite的使用

在VC中对sqlite的使用,实现数据库大批数据的快速插入,读取数据库中的数据在ListCtrl中显示

Flutter组件常见问题整合

Flutter组件常见问题常见问题整合去除按钮点击态(IconButton)文字和数字无法对齐问题字体缩放TextFiled长按显示英文(国际化) 常见问题整合 去除按钮点击态(IconButton) splashColor: Colors.transparent, highlightColor: Colors.transparent, 文字和数字无法对齐问题 在TextStyle 中添加相同的 height即可 注意:height表示行高,显示多行文字时1.0需根据需要调整 TextStyle(

xxx的博客 843

老版QQ原生表情gif动态

这是老版的QQ表情,不过全是动态的的,Windows照片查看器是不会动的,可以右击用浏览器打开查看,再说一遍是老版的,只是分享给宁愿用老版也要动态的人。

Flutter | TextField 禁止开头输入空格(正则)

这是一个很常见的需求,不允许开头输空格。

无夜之星辰的博客 1951

Flutter文本输入框TextField属性(InputDecoration、textInputAction、inputFormatters等等)详解

TextField 构造方法:

喻志强的博客 12万+

Flutter TextField利用 正则和输入监听 设置只能输入零和非零开头的最多带两位小数的数字(整数或小数)

1.在自定义TextInputFormatter中使用正则以及相关逻辑。3.在TextField中使用。

qq_23404533的博客 1311

Flutter: TextEditingValue的实现

如果替换前后的文本长度相同(即 replacementRange.end - replacementRange.start == replacementString.length),则直接调用 copyWith 方法返回新的 TextEditingValue,因为选择范围和组合输入范围不需要调整。例如拼音输入法,在输入字母出现候选字还未确认选择的阶段,composing就为true,当确认选中后,composing就为false。参数:text、selection 和 composing 都是可选参数。

qq_44869043的博客 1240

Flutter中的七种对话框相关组件使用方法

自定义创建。你可以创建自定义对话框以满足特定需求。这通常需要使用Flutter的Widget来构建自定义内容。Text("自定义对话框示例"),Text("这是自定义的内容。"),},child: Text("关闭"),),],),),},

技术应让更广泛的人群流入到实际产品开发中才是正统 1253

flutter 微信输入框 (第二版)

微信的聊天输入框之前实现了一个版本,但是之前实现的不太优雅。这两天重写了一遍。

唐僧的专栏 1674

Flutter 中的 @protected 详解与使用

是 Flutter 中一个功能强大且实用的工具,可以帮助开发者提高代码的封装性、安全性、可重用性。旨在限制成员的可见性,从而提高代码的封装性和安全性。它与 Dart 中的。还可以与其他特性结合使用,实现更加灵活的访问控制。关键字不同,后者仅限于在同一文件中定义的成员可见。可以使代码更加清晰、易懂、易维护。在 Flutter 开发中,除了上述基本用法之外,

爱喝水程序员的博客 824

Flutter完整开发实战详解(一、Dart语言和Flutter基础) | 掘金技术征文

前言  在如今的 Fultter 大潮下,本系列是让你看完会安心的文章。本系列将完整讲述:如何快速从0开发一个完整的 Flutter APP,配套高完成度 Flutter 开源项目 GSYGithubAppFlutter。同时也会提供一些Flutter的开发细节技巧,并针对开发过程中可能遇到的问题进行填坑。  系列文章分为三篇,第一部分是基础篇(针对Dart语言和Flutter基础),第二部分是...

weixin_33997389的博客 901

flutter_weixin聊天界面实现

2、输入的数据用list储存。1、自定义聊天文本框。

scan001111的博客 701

Flutter 注解处理及代码生成

需在定义注解时指定注解被解析时机(编码阶段、源码阶段、运行时阶段),以及注解作用域(类、方法、属性)无需指定注解被解析时机以及注解作用域,默认 Anytime and anywhere在文件中,我们有两个Class使用了注解,其中一个Class除了Class本身以外,它的field 和 function 也使用了注解。但在输出中,我们只拦截到了 ClassOne, 并没有被拦截到 field1 fun1。

2401_84132423的博客 1075
上一篇: flutter聊天界面-TextField输入框buildTextSpan实现@功能展示高亮功能
下一篇: flutter开发实战-长按TextField输入框cut、copy设置为中文复制、粘贴
BruceGwo
博客等级 码龄16年 549粉丝 278原创
评论 1
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值