fleather-editor / fleather

Soft and gentle rich text editing for Flutter applications.
https://fleather-editor.github.io
Other
199 stars 36 forks source link

How to get caret offset? #217

Open nialljawad96 opened 9 months ago

nialljawad96 commented 9 months ago

Is there a way to calculate the offset created by a bullet point (or any other type of block for that matter), relative to a normal line of text?

Amir-P commented 9 months ago

Do you mean the empty space added to the leading of the text in compare to normal paragraphs? Why do you need such a thing?

nialljawad96 commented 8 months ago

@Amir-P hi Amir, thanks for your reply. Yes, i indeed mean that empty space. I'm building a hovering bar (with Bold, Italic etc), like Notion, which needs the TextPosition:

final TextPosition position = TextPosition(offset: controller.selection.baseOffset );

and textSpan painter:

final TextPainter textPainter = TextPainter(
      text: textSpan,
      textDirection: TextDirection.ltr,
    );

to get the caretOffset, so that I can display the bar in the correct place. The problem is that when I use a bullet point (or another block for that matter), it indents it, meaning the textPainter.layout ends up being incorrect by a slight amount. This error builds up the further down the text you try and get the caretOffset, as of course the text is offsetted by more and more bullet points.

Amir-P commented 8 months ago

Hey, in order to get the caret offset without dealing with rendering details you can use the already exposed APIs of RenderEditor and RenderEditableBox. Here is a working code (editorKey is a GlobalKey<EditorState> assigned to FleatherEditor or FleatherField's editorKey parameter):

  Offset getCaretGlobalOffset() {
    final editor = editorKey.currentState!.renderEditor;
    final globalTextPosition = editor.selection.base;
    final childAtPosition = editor.childAtPosition(globalTextPosition);
    final localTextPosition =
        childAtPosition.globalToLocalPosition(globalTextPosition);
    final localOffsetForCaret =
        childAtPosition.getOffsetForCaret(localTextPosition);
    return childAtPosition.localToGlobal(localOffsetForCaret);
  }
nialljawad96 commented 8 months ago

@Amir-P this works perfectly. Genius! Much appreciated, thanks.

Amir-P commented 8 months ago

You're welcome! I'm gonna rename the issue so that other users can find the answer easier.

nialljawad96 commented 7 months ago

For some reason, the offset given by the function above (getCaretGlobalOffset()) is different in these two scenarios:

1) You're typing to a certain position, stop and then calculate the offset. 2) You type to the same position, you stop, click on another part of the text, then click again on the last part of the text you were typing at, and calculate the offset.

The two offsets are the different, even though they should be the same