我想在 Flutter 中创建一个文本字段,当我选择文本的一部分并按下按钮时,只有选定的部分会更改其颜色,例如更改为红色。此外,如果选择文本的另一部分并且其颜色发生变化,则应保留先前文本的样式。
我的目标是修改 Flutter 中文本字段内文本不同部分的颜色。我应该采取哪些步骤来实现这一目标?
我相信最好的方法是使用
SelectableText.rich()
。这不允许您像 TextField
那样编辑文本,因此您要么需要自己实现编辑文本,要么找到一种巧妙的方法在 Stack
中显示它们。
这是一个可以完成您所描述的工作的 Flutter 应用程序:
import 'dart:math';
import 'package:flutter/material.dart';
void main() => runApp(const MyApp());
class MyApp extends StatelessWidget {
const MyApp({super.key});
@override
Widget build(BuildContext context) => const MaterialApp(home: MyHomePage());
}
class MyHomePage extends StatefulWidget {
const MyHomePage({super.key});
@override
State<MyHomePage> createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
static const _text = '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.';
final List<TextStyle> _style = List.filled(_text.length, const TextStyle());
(int startIndex, int endIndex) _selection = (0, 0);
Widget get highlightedText {
final List<TextSpan> children = [];
String currentText = '';
late TextStyle currentStyle;
for (int i = 0; i < _text.length; i++) {
if (currentText.isEmpty) {
currentText = _text[i];
currentStyle = _style[i];
} else {
currentText += _text[i];
if (i + 1 == _text.length || _style[i + 1] != currentStyle) {
children.add(TextSpan(text: currentText, style: currentStyle));
currentText = '';
}
}
}
return SelectableText.rich(
TextSpan(children: children),
onSelectionChanged: (selection, cause) {
final (base, extent) = (selection.baseOffset, selection.extentOffset);
_selection = (min(base, extent), max(base, extent));
},
);
}
void hilight(Color color) {
final (start, end) = _selection;
if (start == end) return;
final style = TextStyle(
color: color.computeLuminance() > 0.25 ? Colors.black : Colors.white,
backgroundColor: color);
for (int i = start; i < end; i++) {
setState(() => _style[i] = style);
}
}
late final Widget highlightButtons = Padding(
padding: const EdgeInsets.only(top: 50, bottom: 25),
child: Row(children: [
for (final color in [
Colors.red,
Colors.orange,
Colors.amber,
Colors.yellow,
Colors.lime,
Colors.green,
Colors.cyan,
Colors.blue,
Colors.indigo,
Colors.purple,
])
_HighlightButton(color: color, onPressed: () => hilight(color))
]),
);
late final Widget resetButton = OutlinedButton(
style: OutlinedButton.styleFrom(foregroundColor: Colors.grey),
onPressed: () {
_selection = (0, _text.length);
hilight(const Color(0x00FFFFFF));
},
child: const Text('reset'),
);
@override
Widget build(BuildContext context) {
return Scaffold(
body: Container(
margin: EdgeInsets.symmetric(horizontal: MediaQuery.of(context).size.width / 16),
alignment: Alignment.center,
child: Column(
mainAxisSize: MainAxisSize.min,
children: [
highlightedText,
highlightButtons,
resetButton,
],
),
),
);
}
}
class _HighlightButton extends StatelessWidget {
const _HighlightButton({required this.color, required this.onPressed});
final Color color;
final void Function() onPressed;
@override
Widget build(BuildContext context) {
return Expanded(
child: Padding(
padding: const EdgeInsets.all(4),
child: ElevatedButton(
style: OutlinedButton.styleFrom(backgroundColor: color),
onPressed: onPressed,
child: const SizedBox.shrink(),
),
),
);
}
}
这是在行动: