Version
16.0.2
Platforms
Android
Device Model
荣耀 MAG AN00
flutter info
[✓] Flutter (Channel stable, 3.32.7, on macOS 15.6.1 24G90 darwin-arm64, locale zh-Hans-CN)
[!] Android toolchain - develop for Android devices (Android SDK version 36.0.0)
! Some Android licenses not accepted. To resolve this, run: flutter doctor --android-licenses
[✓] Xcode - develop for iOS and macOS (Xcode 16.2)
[✓] Chrome - develop for the web
[✓] Android Studio (version 2025.2)
[✓] Android Studio (version 2024.1)
[✓] VS Code (version 1.105.1)
[✓] VS Code (version 1.106.0)
How to reproduce?
你好 我这边遇到如下问题,请教一下如何解决。感谢。
特殊字符影响手动拖拽把手时候被选中的字符的判断。 例如 把 #***^算作一个特殊字符^不显示。
实际字符:你#123456^好#abcdef^啊
显示字符: 你#123456好#abcdef啊
手动拖动把手 选中 : 456好#abc
然后按下删除键,实际被删掉的是 : 56好#abcd,
实际字符:你#123456^好#abcdef^啊
显示字符: 你#123456好#abcdef啊
UI上 选中的是

实际 输出选中的字符为:>>>当前文本选中区域:起始位置=7, 结束位置=16, 选中字符='56^好#abcd'
builder构建代码如下:
Logs
Example code (optional)
class KyyPublishTextSpanBuilder extends SpecialTextSpanBuilder {
final TextStyle? atStyle;
final TextStyle? topicStyle;
final BuildContext? context;
KyyPublishTextSpanBuilder({
this.context,
this.atStyle,
this.topicStyle,
});
@override
TextSpan build(String data,
{TextStyle? textStyle, SpecialTextGestureTapCallback? onTap}) {
var textSpan = super.build(data, textStyle: textStyle, onTap: onTap);
List<TextSpan> result = [];
// 这里额外维护一个全局起始下标,用于构造 SpecialTextSpan 的 textRange,
// 保证后续删除、光标移动等能力能够基于原始文本正确计算位置
int globalStart = 0;
textSpan.children?.forEach((span) {
if (span is SpecialTextSpan) {
// 1、如果已经识别成了特殊文本,那么直接放入result
result.add(span);
} else {
// 2、没有被识别成特殊文本的在这里来提取 特殊文本
// 话题字符:中文/英文/数字
// 话题字符识别有 两种模式, 可以编辑的:#连续话题字符(长度<=15)^ 或者 不可编辑的:#连续话题字符(长度<=15)~
// 使用正则表达式 提取出 span 里面的 话题字符 构建SpecialTextSpan 放入result中,其余字符构建普通TextSpan放入result中,确保其顺序不变
if (span is TextSpan && (span.text?.isNotEmpty ?? false)) {
final String rawText = span.text!;
// 设计说明:
// - 为了兼容两种话题编码形式(可编辑 ^ / 不可编辑 ~),统一用一个正则抽取;
// - 仅允许中英文和数字,长度限制在 1~15 之间,避免出现过长或包含特殊符号的话题。
final RegExp topicReg =
RegExp(r'#([A-Za-z0-9\u4e00-\u9fa5]{0,15})([\^~])');
final Iterable<RegExpMatch> matches = topicReg.allMatches(rawText);
// 如果当前 span 内不存在符合规范的话题串,则直接原样放回,避免多余拆分
if (matches.isEmpty) {
result.add(span);
} else {
int lastIndex = 0;
for (final RegExpMatch match in matches) {
// 先放入话题前面的普通文本
if (match.start > lastIndex) {
result.add(TextSpan(
text: rawText.substring(lastIndex, match.start),
// 优先使用原 span 的样式,其次退回到 builder 传入的 textStyle
style: span.style ?? textStyle,
));
}
final String topicName = match.group(1) ?? '';
// endFlag 目前仅区分是否可编辑,展示内容保持一致,后续如有差异可在这里分支
final String endFlag = match.group(2) ?? '';
// 展示给用户看的文本:不包含结束标记,仅保留 #话题,本地展示不再额外补空格,避免影响排版
final String displayText = '#$topicName';
// 实际文本:保留原始编码(#话题^ 或 #话题~),方便后续服务端/本地解析
final String actualText = '#$topicName$endFlag';
final TextStyle? effectiveStyle =
topicStyle ?? span.style ?? textStyle;
result.add(SpecialTextSpan(
text: displayText,
actualText: actualText,
// 使用全局起点 + 当前匹配在该 span 内的偏移,映射回原始字符串中的位置
start: globalStart + match.start,
style: effectiveStyle,
deleteAll: false,
));
lastIndex = match.end;
}
// 处理最后一个话题之后剩余的普通文本
if (lastIndex < rawText.length) {
result.add(TextSpan(
text: rawText.substring(lastIndex),
style: span.style ?? textStyle,
));
}
}
} else {
// 对于无法识别为 TextSpan 的情况(极少出现),直接保持原样避免破坏结构
result.add(span as TextSpan);
}
}
// 累积当前 span 的纯文本长度,为后续 SpecialTextSpan 提供正确的起点位置
globalStart += span
.toPlainText()
.length;
});
textSpan.children?.clear();
textSpan.children?.addAll(result);
return textSpan;
}
@override
SpecialText? createSpecialText(String flag,
{TextStyle? textStyle,
SpecialTextGestureTapCallback? onTap,
required int index}) {
try {
if (isStart(flag, AtText.atStartFlag)) {
TextStyle tmp = atStyle ?? textStyle!;
return AtText(tmp, (dynamic paramete) {},
start: index - (AtText.atStartFlag.length - 1));
}
} catch (e) {}
return null;
}
}
Contact
No response
Version
16.0.2
Platforms
Android
Device Model
荣耀 MAG AN00
flutter info
How to reproduce?
你好 我这边遇到如下问题,请教一下如何解决。感谢。
特殊字符影响手动拖拽把手时候被选中的字符的判断。 例如 把 #***^算作一个特殊字符^不显示。
实际字符:你#123456^好#abcdef^啊
显示字符: 你#123456好#abcdef啊
手动拖动把手 选中 : 456好#abc
然后按下删除键,实际被删掉的是 : 56好#abcd,
实际字符:你#123456^好#abcdef^啊
显示字符: 你#123456好#abcdef啊
UI上 选中的是
builder构建代码如下:
Logs
Example code (optional)
Contact
No response