gpt4 book ai didi

flutter - 可以在 Flutter 的文本小部件中识别字符的全局位置

转载 作者:行者123 更新时间:2023-12-05 05:07:59 27 4
gpt4 key购买 nike

假设我有一段很长的文本,想在字符 5、10 和 1500 上叠加注释——我如何才能找到这些字符的位置?

我考虑过引用 TextSpan 组件,但是,与 Flutter 的其余部分不同,这些组件不是 Widgets 并且不能有 GlobalKey。

最佳答案

使用 TextPainter 和 Paragraph 很容易(感谢@pskink)。请参阅末尾针对多行网络文本的重要注意事项。

使用 TextPainter

import 'package:flutter/material.dart';

final loremIpsum =
"Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.";

void main() => runApp(MyApp());

class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Welcome to Flutter',
home: Scaffold(
appBar: AppBar(
title: Text('Welcome to Flutter'),
),
body: Center(
child: Container(
width: 350,
color: Color.fromARGB(100, 0, 0, 0),
child: SelectText(),
),
),
),
);
}
}

class SelectText extends StatelessWidget {
@override
Widget build(BuildContext context) {
return LayoutBuilder(
builder: (BuildContext context, BoxConstraints constraints) {
final textPainter = TextPainter(
text: TextSpan(text: loremIpsum),
textDirection: TextDirection.ltr,
);

final width = constraints.maxWidth;
textPainter.layout(
minWidth: 20,
maxWidth: width,
);
final height = textPainter.height;

return Container(
width: width,
height: height,
color: Colors.yellow,
child: GestureDetector(
onTapDown: (details) {
print(
"Selection: ${textPainter.getPositionForOffset(details.localPosition)}");
},
child: CustomPaint(
size: Size(width, height), // Parent width, text height
painter: TextCustomPainter(textPainter),
),
));
});
}
}

class TextCustomPainter extends CustomPainter {
TextPainter textPainter;

TextCustomPainter(this.textPainter, {Listenable? repaint})
: super(repaint: repaint);

@override
void paint(Canvas canvas, Size size) {
textPainter.paint(canvas, Offset(0, 0));
}

@override
bool shouldRepaint(CustomPainter old) {
return false;
}
}

带段落

import 'package:flutter/material.dart';
import 'dart:ui';
import 'dart:ui' as ui;

final loremIpsum =
"Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.";

void main() => runApp(MyApp());

class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Welcome to Flutter',
home: Scaffold(
appBar: AppBar(
title: Text('Welcome to Flutter'),
),
body: Center(
child: Container(
width: 350,
color: Color.fromARGB(100, 0, 0, 0),
child: SelectText(),
),
),
),
);
}
}

class SelectText extends StatelessWidget {
@override
Widget build(BuildContext context) {
final TextStyle style = TextStyle(
color: Colors.black,
);

// Set width to max allowed by parent
return LayoutBuilder(
builder: (BuildContext context, BoxConstraints constraints) {
final ui.ParagraphBuilder paragraphBuilder = ui.ParagraphBuilder(
ui.ParagraphStyle(
fontSize: style.fontSize,
// There unfortunelly are some things to be copied from your common TextStyle to ParagraphStyle :C
fontFamily: style.fontFamily,
// IDK why it is like this, this is somewhat weird especially when there is `pushStyle` which can use the TextStyle...
fontStyle: style.fontStyle,
fontWeight: style.fontWeight,
textAlign: TextAlign.justify,
//maxLines: 25,
))
..pushStyle(style
.getTextStyle()) // To use multiple styles, you must make use of the builder and `pushStyle` and then `addText` (or optionally `pop`).
..addText(loremIpsum);

final width = constraints.maxWidth;
final ui.Paragraph paragraph = paragraphBuilder.build()
..layout(ui.ParagraphConstraints(width: width));

paragraph.layout(ParagraphConstraints(
width: width,
));
final height = paragraph.height;

return Container(
width: width,
height: height,
color: Colors.yellow,
child: GestureDetector(
onTapDown: (details) {
// BUG. On web- position is only correct for first line.
print(
"Selection: ${paragraph.getPositionForOffset(details.localPosition)}");
},
child: CustomPaint(
size: Size(width, height), // Parent width, text height
painter: TextCustomPainter(paragraph),
),
));
});
}
}

class TextCustomPainter extends CustomPainter {
Paragraph paragraph;

TextCustomPainter(this.paragraph, {Listenable repaint})
: super(repaint: repaint);

@override
void paint(Canvas canvas, Size size) {
canvas.drawParagraph(paragraph, const Offset(0, 0));
}

@override
bool shouldRepaint(CustomPainter old) {
return false;
}
}

网络警告

以上两种方法目前都无法用于网络,因为它们只能正确报告第一行文本的文本位置,而对于多行文本则完全无法使用。请参阅:https://github.com/flutter/flutter/issues/44121一年多以来,这一直是 web 的一个开放错误,这里的事件非常缓慢。不要指望很快就会有修复。目前,在使用 FLUTTER_WEB_USE_EXPERIMENTAL_CANVAS_TEXT 编译并使用 --release 编译的 master 分支 IFF 中修复了一些不良行为,使您的项目不可调试!

flutter build web  --release --dart-define=FLUTTER_WEB_USE_EXPERIMENTAL_CANVAS_TEXT=true

Flutter 可以使用对 TextWidget 的简单添加来使此功能更容易使用:-/

关于flutter - 可以在 Flutter 的文本小部件中识别字符的全局位置,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/58635800/

27 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com