String 不是 well-formed utf-16,而关键是要使用更多的符号!例如心脏或象形文字

String is not well-formed utf-16, while the point is to use more symbols! for instance heart or a Hieroglyph

我是一个飞镖小白,想做一个键盘上有符号和象形文字的键盘,所以这是我的尝试! 但是当我使用退格键时,它吓坏了: 项目在 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.

这个问题和这个答案与文章原始版本的一个问题有关Custom In-App Keyboard in 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

请参阅有关删除大于单个代理项对的字素簇的相关问题:

  • How to convert String index to character index in Dart