Из того, что я могу сказать, у Dart нет поддержки кластеров графем, хотя есть разговоры о его поддержке:
До тех пор, пока он не будет реализован, каковы мои варианты перебора кластеров графем?Например, если у меня есть строка, подобная этой:
String family = '\u{1F468}\u{200D}\u{1F469}\u{200D}\u{1F467}'; // ???
String myString = 'Let me introduce my $family to you.';
, и после семейства emoji с пятью кодами есть курсор:
Как бы я переместил курсор на один воспринимаемый пользователем символ влево?
(В данном конкретном случае я знаю размер кластера графем, чтобы я мог это сделать, но я действительно спрашиваю о том, как найти длину произвольно длинного кластера графем.)
Обновление
Из этой статьи я вижу, что Swift использует системную библиотеку ICU .Нечто подобное может быть возможно во Flutter.
Дополнительный код
Для тех, кто хочет поиграть с моим примером выше, вот демонстрационный проект.Кнопки перемещают курсор вправо или влево.В настоящее время требуется 8 нажатий кнопок для перемещения курсора мимо семейства смайликов.
main.dart
import 'package:flutter/material.dart';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
appBar: AppBar(title: Text('Grapheme cluster testing')),
body: BodyWidget(),
),
);
}
}
class BodyWidget extends StatefulWidget {
@override
_BodyWidgetState createState() => _BodyWidgetState();
}
class _BodyWidgetState extends State<BodyWidget> {
TextEditingController controller = TextEditingController(
text: 'Let me introduce my \u{1F468}\u{200D}\u{1F469}\u{200D}\u{1F467} to you.'
);
@override
Widget build(BuildContext context) {
return Column(
children: <Widget>[
TextField(
controller: controller,
),
Row(
children: <Widget>[
Padding(
padding: const EdgeInsets.all(8.0),
child: RaisedButton(
child: Text('<<'),
onPressed: () {
_moveCursorLeft();
},
),
),
Padding(
padding: const EdgeInsets.all(8.0),
child: RaisedButton(
child: Text('>>'),
onPressed: () {
_moveCursorRight();
},
),
),
],
)
],
);
}
void _moveCursorLeft() {
int currentCursorPosition = controller.selection.start;
if (currentCursorPosition == 0)
return;
int newPosition = currentCursorPosition - 1;
controller.selection = TextSelection(baseOffset: newPosition, extentOffset: newPosition);
}
void _moveCursorRight() {
int currentCursorPosition = controller.selection.end;
if (currentCursorPosition == controller.text.length)
return;
int newPosition = currentCursorPosition + 1;
controller.selection = TextSelection(baseOffset: newPosition, extentOffset: newPosition);
}
}