Строка не является правильно сформированной utf-16, а смысл в том, чтобы использовать больше символов! например сердце или иероглиф

Я нуб в дартс, и хотел бы сделать клавиатуру с символами и иероглифами в клавиатуре, так что это моя попытка! но когда я использую backspace, это сходит с ума: проект с открытым исходным кодом на github: https://github.com/bookla-foundation/hieroglyphs ошибка:

For more information see https://dart.dev/null-safety/unsound-null-safety
I/flutter ( 4728): ══╡ EXCEPTION CAUGHT BY RENDERING LIBRARY ╞═════════════════════════════════════════════════════════
I/flutter ( 4728): The following ArgumentError was thrown during performLayout():
I/flutter ( 4728): Invalid argument(s): string is not well-formed UTF-16
I/flutter ( 4728):
I/flutter ( 4728): The relevant error-causing widget was:
I/flutter ( 4728):   TextField file:///Users/xxx/workspace/dart/heeroghleefy/lib/main.dart:30:11
I/flutter ( 4728):
I/flutter ( 4728): When the exception was thrown, this was the stack:
I/flutter ( 4728): #0      ParagraphBuilder.addText (dart:ui/text.dart:2178:7)
I/flutter ( 4728): #1      TextSpan.build (package:flutter/src/painting/text_span.dart:210:15)
I/flutter ( 4728): #2      TextPainter.layout (package:flutter/src/painting/text_painter.dart:569:14)
I/flutter ( 4728): #3      RenderEditable._layoutText (package:flutter/src/rendering/editable.dart:2011:18)
I/flutter ( 4728): #4      RenderEditable.performLayout (package:flutter/src/rendering/editable.dart:2059:5)
I/flutter ( 4728): #5      RenderObject.layout (package:flutter/src/rendering/object.dart:1777:7)
I/flutter ( 4728): #6      RenderProxyBoxMixin.performLayout (package:flutter/src/rendering/proxy_box.dart:123:14)
I/flutter ( 4728): #7      RenderObject.layout (package:flutter/src/rendering/object.dart:1777:7)
I/flutter ( 4728): #8      RenderProxyBoxMixin.performLayout (package:flutter/src/rendering/proxy_box.dart:123:14)
I/flutter ( 4728): #9      RenderLeaderLayer.performLayout (package:flutter/src/rendering/proxy_box.dart:5034:11)
I/flutter ( 4728): #10     RenderObject.layout (package:flutter/src/rendering/object.dart:1777:7)
I/flutter ( 4728): #11     RenderProxyBoxMixin.performLayout (package:flutter/src/rendering/proxy_box.dart:123:14)
I/flutter ( 4728): #12     RenderObject.layout (package:flutter/src/rendering/object.dart:1777:7)
I/flutter ( 4728): #13     RenderProxyBoxMixin.performLayout (package:flutter/src/rendering/proxy_box.dart:123:14)
I/flutter ( 4728): #14     RenderObject.layout (package:flutter/src/rendering/object.dart:1777:7)
I/flutter ( 4728): #15     RenderProxyBoxMixin.performLayout (package:flutter/src/rendering/proxy_box.dart:123:14)
I/flutter ( 4728): #16     RenderObject.layout (package:flutter/src/rendering/object.dart:1777:7)
I/flutter ( 4728): #17     RenderProxyBoxMixin.performLayout (package:flutter/src/rendering/proxy_box.dart:123:14)
I/flutter ( 4728): #18     RenderObject.layout (package:flutter/src/rendering/object.dart:1777:7)
I/flutter ( 4728): #19     RenderProxyBoxMixin.performLayout (package:flutter/src/rendering/proxy_box.dart:123:14)
I/flutter ( 4728): #20     RenderObject.layout (package:flutter/src/rendering/object.dart:1777:7)
I/flutter ( 4728): #21     RenderProxyBoxMixin.performLayout (package:flutter/src/rendering/proxy_box.dart:123:14)
I/flutter ( 4728): #22     RenderCustomPaint.performLayout (package:flutter/src/rendering/custom_paint.dart:518:11)
I/flutter ( 4728): #23     RenderObject.layout (package:flutter/src/rendering/object.dart:1777:7)
I/flutter ( 4728): #24     RenderProxyBoxMixin.performLayout (package:flutter/src/rendering/proxy_box.dart:123:14)
I/flutter ( 4728): #25     RenderObject.layout (package:flutter/src/rendering/object.dart:1777:7)
I/flutter ( 4728): #26     RenderProxyBoxMixin.performLayout (package:flutter/src/rendering/proxy_box.dart:123:14)
I/flutter ( 4728): #27     RenderObject.layout (package:flutter/src/rendering/object.dart:1777:7)
I/flutter ( 4728): #28     RenderProxyBoxMixin.performLayout (package:flutter/src/rendering/proxy_box.dart:123:14)
I/flutter ( 4728): #29     RenderObject.layout (package:flutter/src/rendering/object.dart:1777:7)
I/flutter ( 4728): #30     _RenderDecoration._layoutLineBox (package:flutter/src/material/input_decorator.dart:931:9)
I/flutter ( 4728): #31     _RenderDecoration._layout (package:flutter/src/material/input_decorator.dart:1033:28)
I/flutter ( 4728): #32     _RenderDecoration.performLayout (package:flutter/src/material/input_decorator.dart:1294:44)
I/flutter ( 4728): #33     RenderObject.layout (package:flutter/src/rendering/object.dart:1777:7)
I/flutter ( 4728): #34     RenderProxyBoxMixin.performLayout (package:flutter/src/rendering/proxy_box.dart:123:14)
I/flutter ( 4728): #35     RenderObject.layout (package:flutter/src/rendering/object.dart:1777:7)
I/flutter ( 4728): #36     RenderProxyBoxMixin.performLayout (package:flutter/src/rendering/proxy_box.dart:123:14)
I/flutter ( 4728): #37     RenderObject.layout (package:flutter/src/rendering/object.dart:1777:7)
I/flutter ( 4728): #38     RenderProxyBoxMixin.performLayout (package:flutter/src/rendering/proxy_box.dart:123:14)
I/flutter ( 4728): #39     RenderObject.layout (package:flutter/src/rendering/object.dart:1777:7)
I/flutter ( 4728): #40     RenderProxyBoxMixin.performLayout (package:flutter/src/rendering/proxy_box.dart:123:14)
I/flutter ( 4728): #41     RenderObject.layout (package:flutter/src/rendering/object.dart:1777:7)
I/flutter ( 4728): #42     ChildLayoutHelper.layoutChild (package:flutter/src/rendering/layout_helper.dart:54:11)
I/flutter ( 4728): #43     RenderFlex._computeSizes (package:flutter/src/rendering/flex.dart:830:43)
I/flutter ( 4728): #44     RenderFlex.performLayout (package:flutter/src/rendering/flex.dart:932:32)
I/flutter ( 4728): #45     RenderObject.layout (package:flutter/src/rendering/object.dart:1777:7)
I/flutter ( 4728): #46     MultiChildLayoutDelegate.layoutChild (package:flutter/src/rendering/custom_layout.dart:171:12)
I/flutter ( 4728): #47     _ScaffoldLayout.performLayout (package:flutter/src/material/scaffold.dart:912:7)
I/flutter ( 4728): #48     MultiChildLayoutDelegate._callPerformLayout (package:flutter/src/rendering/custom_layout.dart:243:7)
I/flutter ( 4728): #49     RenderCustomMultiChildLayoutBox.performLayout (package:flutter/src/rendering/custom_layout.dart:407:14)
I/flutter ( 4728): #50     RenderObject._layoutWithoutResize (package:flutter/src/rendering/object.dart:1634:7)
I/flutter ( 4728): #51     PipelineOwner.flushLayout (package:flutter/src/rendering/object.dart:884:18)
I/flutter ( 4728): #52     RendererBinding.drawFrame (package:flutter/src/rendering/binding.dart:455:19)
I/flutter ( 4728): #53     WidgetsBinding.drawFrame (package:flutter/src/widgets/binding.dart:903:13)
I/flutter ( 4728): #54     SchedulerBinding._invokeFrameCallback (package:flutter/src/scheduler/binding.dart:1119:15)
I/flutter ( 4728): #55     SchedulerBinding.handleDrawFrame (package:flutter/src/scheduler/binding.dart:1057:9)
I/flutter ( 4728): #59     _invoke (dart:ui/hooks.dart:157:10)
I/flutter ( 4728): #60     PlatformDispatcher._drawFrame (dart:ui/platform_dispatcher.dart:253:5)
I/flutter ( 4728): #61     _drawFrame (dart:ui/hooks.dart:120:31)
I/flutter ( 4728): (elided 3 frames from dart:async)
I/flutter ( 4728):
I/flutter ( 4728): The following RenderObject was being processed when the exception was fired: RenderEditable#d149e relayoutBoundary=up18 NEEDS-LAYOUT NEEDS-PAINT:
I/flutter ( 4728):   creator: _Editable-[GlobalKey#5bfdd] ← Semantics ← CompositedTransformTarget ←
I/flutter ( 4728):     IgnorePointer-[GlobalKey#826e3] ← Semantics ← Listener ←
I/flutter ( 4728):     RawGestureDetector-[LabeledGlobalKey<RawGestureDetectorState>#e8b2c] ← Listener ← _ScrollableScope
I/flutter ( 4728):     ← RepaintBoundary ← CustomPaint ← RepaintBoundary ← ⋯
I/flutter ( 4728):   parentData: <none> (can use size)
I/flutter ( 4728):   constraints: BoxConstraints(w=387.4, 0.0<=h<=Infinity)
I/flutter ( 4728):   size: Size(387.4, 32.0)
I/flutter ( 4728):   cursorColor: Color(0xff2196f3)
I/flutter ( 4728):   showCursor: ValueNotifier<bool>#d5002(true)
I/flutter ( 4728):   maxLines: 1
I/flutter ( 4728):   minLines: null
I/flutter ( 4728):   selectionColor: Color(0x662196f3)
I/flutter ( 4728):   textScaleFactor: 1.0
I/flutter ( 4728):   locale: en_US
I/flutter ( 4728):   selection: TextSelection(baseOffset: 5, extentOffset: 5, affinity: TextAffinity.downstream,
I/flutter ( 4728):     isDirectional: false)
I/flutter ( 4728):   offset: ScrollPositionWithSingleContext#51e24(offset: 0.0, range: 0.0..0.0, viewport: 387.4,
I/flutter ( 4728):     ScrollableState, ClampingScrollPhysics -> RangeMaintainingScrollPhysics, IdleScrollActivity#4e8d9,
I/flutter ( 4728):     ScrollDirection.idle)
I/flutter ( 4728): This RenderObject had the following child:
I/flutter ( 4728):     text: TextSpan
I/flutter ( 4728): ════════════════════════════════════════════════════════════════════════════════════════════════════
I/flutter ( 4728): Another exception was thrown: Null check operator used on a null value
I/chatty  ( 4728): uid=10135(com.example.heeroghleefy) 1.ui identical 2 lines
I/flutter ( 4728): Another exception was thrown: Null check operator used on a null value
I/flutter ( 4728): Another exception was thrown: Null check operator used on a null value
I/flutter ( 4728): Another exception was thrown: Null check operator used on a null value
I/flutter ( 4728): Another exception was thrown: Null check operator used on a null value
I/flutter ( 4728): Another exception was thrown: Null check operator used on a null value
I/flutter ( 4728): Another exception was thrown: Please see the documentation for computeDistanceToActualBaseline for the required calling conventions of this method.

person Omar S.    schedule 24.12.2020    source источник
comment
Можете ли вы также опубликовать код, вызвавший ошибку?   -  person Suragch    schedule 24.12.2020
comment
обновил, сорри. ошибка возникает при нажатии backspace после ввода символа из иероглифов   -  person Omar S.    schedule 24.12.2020
comment
Вы нажали свои изменения? Main.dart по-прежнему остается оригинальным.   -  person Suragch    schedule 24.12.2020
comment
Но я почти уверен, что это из-за проблем utf-16 с иероглифами. Вы можете использовать pub.dev/packages/characters, чтобы исправить это.   -  person Suragch    schedule 24.12.2020
comment
medium.com/flutter-community/   -  person Suragch    schedule 24.12.2020
comment
извините, только что отправил последнюю версию на github @Suragch   -  person Omar S.    schedule 24.12.2020


Ответы (1)


Вопрос и этот ответ связаны с проблемой оригинальной версии статьи Пользовательская клавиатура в приложении во Flutter. Статья была обновлена, поэтому возврат назад больше не должен вызывать сбой.

Проблема была вызвана попыткой удалить только половину суррогатной пары. Способ исправить это, чтобы проверить наличие суррогатов перед удалением:

void _backspace() {
  final text = _controller.text;
  final textSelection = _controller.selection;
  final selectionLength = textSelection.end - textSelection.start;

  // There is a selection.
  if (selectionLength > 0) {
    final newText = text.replaceRange(
      textSelection.start,
      textSelection.end,
      '',
    );
    _controller.text = newText;
    _controller.selection = textSelection.copyWith(
      baseOffset: textSelection.start,
      extentOffset: textSelection.start,
    );
    return;
  }

  // The cursor is at the beginning.
  if (textSelection.start == 0) {
    return;
  }

  // Delete the previous character
  final previousCodeUnit = text.codeUnitAt(textSelection.start - 1);
  final offset = _isUtf16Surrogate(previousCodeUnit) ? 2 : 1;
  final newStart = textSelection.start - offset;
  final newEnd = textSelection.start;
  final newText = text.replaceRange(
    newStart,
    newEnd,
    '',
  );
  _controller.text = newText;
  _controller.selection = textSelection.copyWith(
    baseOffset: newStart,
    extentOffset: newStart,
  );
}

bool _isUtf16Surrogate(int value) {
  return value & 0xF800 == 0xD800;
}

_controller относится к TextEditingController вместо TextField.

См. этот связанный вопрос об удалении кластеров графем, превышающих одну суррогатную пару:

person Suragch    schedule 25.12.2020