Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add WidgetSpan support for TextField/RenderEditable #30688

Closed
znshje opened this issue Apr 8, 2019 · 69 comments
Closed

Add WidgetSpan support for TextField/RenderEditable #30688

znshje opened this issue Apr 8, 2019 · 69 comments
Labels
a: text input Entering text in a text field or keyboard related problems c: new feature Nothing broken; request for a new capability c: proposal A detailed proposal for a change to Flutter f: material design flutter/packages/flutter/material repository. framework flutter/packages/flutter repository. See also f: labels. P1 High-priority issues at the top of the work list waiting for customer response The Flutter team cannot make further progress on this issue until the original reporter responds

Comments

@znshje
Copy link

znshje commented Apr 8, 2019

I don't need a passage editor like Zefyr which has styles like BOLD and ITALIC, what I want is a text field in which I can insert plain text, inline image(faces/emoji), block image, mention symbol(@) and topic symbol(#topic#).
It can be implemented on Android by SpannableString. I hope I can do it on Flutter, too.
So anyone knows how to do this?

@HansMuller HansMuller added a: text input Entering text in a text field or keyboard related problems f: material design flutter/packages/flutter/material repository. framework flutter/packages/flutter repository. See also f: labels. labels Jun 21, 2019
@HansMuller
Copy link
Contributor

cc @GaryQian

@GaryQian GaryQian added the c: new feature Nothing broken; request for a new capability label Jun 21, 2019
@GaryQian
Copy link
Contributor

Text.rich supports building text from a tree of InlineSpans, which in turn support any of the properties in TextStyle. We have recently added support for inline widgets. Simply include a WidgetSpan in your InlineSpan tree. This includes images, as well as any other arbitrary widget. You can add a @ symbol and make it linkable by adding a GestureRecognizer in a TextSpan.

Please refer to our (master channel) docs for more info.

@heinrichreimer
Copy link

@GaryQian I don't think you've fully understood the issue.
There is Text.rich() which allows for formatting a TextWidget, but there is no TextField which could be styled like that.

@GaryQian GaryQian reopened this Jul 12, 2019
@GaryQian
Copy link
Contributor

Ahh I see, my bad! I don't think there is a built in way right now, but the building blocks are there, it is a matter of assembling them such that we allow inputting custom InlineSpan trees into a text field.

@Sp4Rx
Copy link

Sp4Rx commented Jul 24, 2019

Could you elaborate about the implementation? @GaryQian

@GaryQian
Copy link
Contributor

So what kind of functionality would you require for this "Rich TextField"? We currently have the InlineSpan tree API that allows you to build a tree of InlineSpan objects that inherit TextStyles.

Would the functionality of being able to append independently styled InlineSpans to the contents of the TextField be sufficient?

@Sp4Rx
Copy link

Sp4Rx commented Jul 25, 2019

As I can see from InlineSpan example that it can have multiple TextField with different styles. But I want a single TextField where I can insert different styles just like RichText. For example take Facebook's or any major platform's @mention. In java I have done this with SpannableString like @nullptrjzz mentioned.

@GaryQian
Copy link
Contributor

Well since we don't have this explicit capability yet, it would be helpful if you could provide pseudo/fake sample code on how you would like the API to work.

There are a couple of ways this could work, one of them being keeping a stack of TextStyles and push/pop methods. Any text inserted through keyboard or through a manual method would then have the style the top TextStyle in the stack. This system would be very similar to our existing ParagraphBuilder works.

Other approaches could be either more or less structured, but it would be very helpful to have examples of the kind of code you want to be able to write to achieve what you want. Feel free to make up methods/classes/API! This way, we can add the functionality that would best fit your (and other's uses)

@Sp4Rx
Copy link

Sp4Rx commented Jul 27, 2019

Flutter has a class called Chip. I don't know it is the right question to ask or not, is it possible to insert Chip in TextField?

As flutter don't provide inserting styling by positions like SpannableString so I can think of the pseudo code similar to RichText

//pseudo code
RichTextField(
  style: DefaultTextStyle.of(context).style,
  children: <SubTextField>[
    SubTextField(
      style: TextStyle(
        color: Colors.white,
      ),
    ),
    SubTextField(),
  ],
)

@seeps001
Copy link

Any thoughts on a core rich text plugin similar to CKEditor?

@gerry05
Copy link

gerry05 commented Jul 29, 2019

how to get the url/image of GIF in keyboard? I got this message when I try to select a gif. App Name doesn't support image insertion here.

@TonAbs
Copy link

TonAbs commented Aug 4, 2019

Perhaps this package can help!
https://pub.dev/packages/extended_text_field#-readme-tab-

@Sp4Rx
Copy link

Sp4Rx commented Aug 4, 2019

extended_text_field Looks promising , I will implement and share my feedback.

@GaryQian
Copy link
Contributor

GaryQian commented Aug 8, 2019

We may be able to work with the author of that package to see if we can come up with a reasonable way to integrate some of its core features directly and efficiently into Flutter, as it seems that package accomplishes much of what is being requested here. I'll reach out!

For now, the extended_text_field looks like a good solution to achieve the desired effect.

@giacomoran
Copy link

Has there been any progress on this issue?

@TonAbs
Copy link

TonAbs commented Nov 17, 2019

You can now override the buildTextSpan method in the textEditingController to achieve the desired effect

@giacomoran
Copy link

True.
It is not complete though.
I can add custom styles to TextSpans, as you say. Now I'm on my way to add WidgetSpan support, RenderEditable does not support it yet.
Is anybody else working on this?

@GaryQian GaryQian changed the title Is there a way to implement Rich Textfield? WidgetSpan support for TextField/RenderEditable Nov 20, 2019
@GaryQian GaryQian changed the title WidgetSpan support for TextField/RenderEditable Add WidgetSpan support for TextField/RenderEditable Nov 20, 2019
@GaryQian
Copy link
Contributor

I have not been able to get to it yet. If someone has the time, I would be happy to review any PRs for this feature. You should be able to use RenderParagraph's impl as a guide.

I'll try my best to get to this eventually, but have higher priority/sensitive issues to tackle at the moment.

@GaryQian GaryQian added this to the Near-term Goals milestone Nov 20, 2019
@giacomoran
Copy link

Thank you!
I got a basic version working, basically by fitting RenderParagraph stuff into RenderEditable.
Now I'm focusing on something else, but will get back to it soon.

It would be awesome to have Flutter support this without having to reimplement EditableText and so on, so I'll be happy to help.

@Ahmadre
Copy link

Ahmadre commented Dec 26, 2019

@ALL any updates?

@gliese667c
Copy link

Any NEW updates?

@MatrixDev
Copy link

@Teio07 it actually should be pretty easy to do by just wrapping part of text into WidgetSpan and add paddings or whatever. Unfortunately you can't do this because TextField/RenderEditable doesn't support WidgetSpan and will just crash.

@TeddyLourson
Copy link

TeddyLourson commented May 12, 2021

@MatrixDev I'm not sure I could do it this way since WidgetSpan takes a Widget as a child which TextSpan isn't and I think RenderEditable uses TextSpans to calculate metrics using TextPainter so I think the only way would be to override buildTextSpan and build paragraphs like this :

TextSpan(children: [
      // Paragraph 1
      TextSpan(children: [
        WidgetSpan(
          child: SizedBox(width: paddingLeftParagraph1),
        ),
        TextSpan(textForParagraph1),
      ]),

      // Paragraph 2
      TextSpan(children: [
        WidgetSpan(
          child: SizedBox(width: paddingLeftParagraph2),
        ),
        TextSpan(textForParagraph2),
      ]),

      // Paragraph 3
      TextSpan(children: [
        WidgetSpan(
          child: SizedBox(width: paddingLeftParagraph3),
        ),
        TextSpan(textForParagraph3),
      ]),
    ]);

But, then I have no idea how to deal with right side padding... 😕

Edit : I’m not even sure it would work since the next line of the same paragraph would not be affected by the SizedBox‘s width... I’ll take a look at the FlutterQuill package.

@radoslaw-sz
Copy link

Hello @GaryQian ,
This is very expected feature from my point of view and I am very thankful that you are working on it.
One question from my side - how text field will be rendered after editing it? We have already couple of rich text editors built in flutter, but I am struggling with one problem - when I am editing the whole text field, all widgets are being rebuilt constantly (e.g. singerdmx/flutter-quill#89 (comment)).
Do you know how it would be done here? Will widgetSpan be constantly rebuilding because of editing the text field? I believe all is about internal implementation - most (all?) current text editors went through whole text and built all widgets from the beginning.

@MatrixDev
Copy link

@mordivgor, I really don't think (yet hope) they will implement dynamic/editable spans like Editable in Android. It'll most probably will require complete rewrite of current span implementation. I hope they at least implement WidgetSpan without big compromises.

@devilyard
Copy link

any updates for this?

@GaryQian
Copy link
Contributor

GaryQian commented Jun 1, 2021

I will be attempting to land this as two parts:

  • The core WidgetSpan rendering support in RenderEditable
  • User-friendly API to handle the TextEditingValue -> TextSpan+WidgetSpan conversion process.

The core rendering support will land first, which will allow more advanced users to begin modifying their TextEditingControllers to provide to RenderEditable. The second part requires more detailed planning and work.

@GaryQian
Copy link
Contributor

Core widgetspan support has landed. RenderEditable, and by extension, textfields, can now display WidgetSpans if the TextEditingController outputs WidgetSpans.

@spideythewebhead
Copy link

Hello! In what version is this api available? I am currently using 2.2.1, i was reading through TextEditingController
and i saw this method TextSpan buildTextSpan({required BuildContext context, TextStyle? style , required bool withComposing}) {..}, in the comments it says we should override this if we want to provide customized text.

I wrote this function

  @override
  TextSpan buildTextSpan({required BuildContext context, TextStyle? style, required bool withComposing}) {
    final atIndex = text.indexOf('@');
    var spans = <InlineSpan>[];

    if (atIndex != -1) {
      spans.add(TextSpan(text: text.substring(0, atIndex)));
      spans.add(
        WidgetSpan(
          alignment: PlaceholderAlignment.middle,
          child: Card(
            child: Padding(
              padding: const EdgeInsets.all(4.0),
              child: Text('@'),
            ),
          ),
        ),
      );
      spans.add(TextSpan(text: text.substring(1 + atIndex)));
    } else {
      spans.add(TextSpan(text: text));
    }

    return TextSpan(
      children: spans,
    );
  }

What is does, it replaces the @ symbol with a widget, but this crashes with this assertion
'package:flutter/src/widgets/widget_span.dart': Failed assertion: line 105 pos 12: 'dimensions != null': is not true.

I probably dont understand how it should be done, is there any guide or its not available yet? thanks!

@Paul-cbt
Copy link

Hello @spideythewebhead, I have also rewrote the buildTextSpan method, but as soon as I add a WidgetSpan into the mix:

The following assertion was thrown during performLayout():
Assertion failed:
..\…\widgets\widget_span.dart:105
dimensions != null
is not true


The relevant error-causing widget was
TextField-[GlobalKey#d0c03 rectoinputText]
lib\…\flashCardCreate_tile\flashcardcreate_tile.dart:1972
When the exception was thrown, this was the stack
C:/b/s/w/ir/cache/builder/src/out/host_debug/dart-sdk/lib/_internal/js_dev_runtime/private/ddc_runtime/errors.dart 236:49  throw_
C:/b/s/w/ir/cache/builder/src/out/host_debug/dart-sdk/lib/_internal/js_dev_runtime/private/ddc_runtime/errors.dart 29:3    assertFailed
packages/flutter/src/widgets/widget_span.dart 105:22                                                                       build
packages/flutter/src/painting/text_span.dart 252:14                                                                        build
packages/flutter/src/painting/text_painter.dart 569:7                                                                      layout
...
The following RenderObject was being processed when the exception was fired: RenderEditable#a1504 relayoutBoundary=up73 NEEDS-LAYOUT NEEDS-PAINT NEEDS-COMPOSITING-BITS-UPDATE
RenderObject: RenderEditable#a1504 relayoutBoundary=up73 NEEDS-LAYOUT NEEDS-PAINT NEEDS-COMPOSITING-BITS-UPDATE
    parentData: <none> (can use size)
    constraints: BoxConstraints(w=1335.8, 0.0<=h<=Infinity)
    size: MISSING
    cursorColor: Color(0x00f46b45)
    showCursor: ValueNotifier<bool>#47e2f(true)
    maxLines: null
    minLines: 1
    selectionColor: Color(0x662196f3)
    textScaleFactor: 1.0
    locale: en_US
    selection: TextSelection(baseOffset: -1, extentOffset: -1, affinity: TextAffinity.downstream, isDirectional: false)
    offset: ScrollPositionWithSingleContext#4e4f3(offset: 0.0, range: null..null, viewport: null, ScrollableState, ClampingScrollPhysics -> RangeMaintainingScrollPhysics, IdleScrollActivity#e2324, ScrollDirection.idle)
    text: TextSpan
        debugLabel: (englishLike subhead 2014).merge((blackRedmond subtitle1).apply)
        inherit: false
        color: Color(0xdd000000)
        family: Noto
        size: 16.0
        weight: 400
        baseline: alphabetic
Assertion failed:
..\…\rendering\box.dart:1930
hasSize
"RenderBox was not laid out: RenderSemanticsAnnotations#17089 relayoutBoundary=up69 NEEDS-PAINT NEEDS-COMPOSITING-BITS-UPDATE"

The relevant error-causing widget was
TextField-[GlobalKey#d0c03 rectoinputText]
lib\…\flashCardCreate_tile\flashcardcreate_tile.dart:1972

@spideythewebhead
Copy link

@GaryQian Hi, any idea for this problem?

@jasonhoo95
Copy link

r

I'm trying to implement it by myself and got something "kind of working".

This is the piece of code I put inside the "buildTextSpan" method of TextEditingController :
Capture d’écran 2021-03-20 à 14 48 21

And what it looks like in action :

WidgetSpan_Offset_Problem.mov
As you can see there's an offset problem of two characters because of the two WidgetSpans added before the TextSpan. There's also the problem of the cursor not adapting its height to the WidgetSpan.
I just did what @GaryQian said above and took a look at RenderParagraph and Copy-Pasted some code inside RenderEditable (as well as some minor modifications inside EditableText).
I'll try and read those file and see if I can solve those problems.

I'm also building a RichTextField using the default TextField Widget Flutter is offering and it looks kind of promising, here's a peek :

RichTextField_Peek.mov
You'll be able to customize the toolbar or provide your own and create as many styles as you want.

Hi do u mind sharing your code to me for the rich textfield it looks really cool, and i need to implement that

@jasonhoo95
Copy link

Screenshot 2021-07-19 at 8 50 37 PM

Any idea how to solve this, the text span of textfield when i set background colour to it, the selection highlight colour will not be visible anymore, i think this is a bug need to fix, am I right? or there is a way to fix this?

@GaryQian
Copy link
Contributor

@jasonhoo95 This particular issue is actually more difficult to solve depending on what you want. Currently, the background color is drawn as part of the text layout and painting, while the selection highlight is drawn separately. We are presented with two options: Draw highlight behind the text (including the bg) or over the text (including bg). For most cases, drawing behind is correct as we want the text to remain readable. However, in this case, the bg just ends up obscuring the highlight.

You could try modifying RenderEditable to paint the highlight after the text and playing with the opacity, but it would still obscure the text. Slipping the highlight between the text and the bg is a fairly complex change that modifies the layout engine and I don't think there is enough demand for that capability to justify it as of now.

@jasonhoo95
Copy link

jasonhoo95 commented Jul 22, 2021

@GaryQian Hmm but can I ask, in ios native layout engine is possible to set the highlight to overlay above the bg and text am I right? Oo man this is bad, i was really hope to develop an app with rich textfield with flutter, cause flutter it is really easy to use, looks like now is not going to happen, but in the future will u able to fix it with highlight overlay on top bg?

@derkro99
Copy link

derkro99 commented Aug 23, 2021

Hello @spideythewebhead, I have also rewrote the buildTextSpan method, but as soon as I add a WidgetSpan into the mix:

The following assertion was thrown during performLayout():
Assertion failed:
..\…\widgets\widget_span.dart:105
dimensions != null
is not true


The relevant error-causing widget was
TextField-[GlobalKey#d0c03 rectoinputText]
lib\…\flashCardCreate_tile\flashcardcreate_tile.dart:1972
When the exception was thrown, this was the stack
C:/b/s/w/ir/cache/builder/src/out/host_debug/dart-sdk/lib/_internal/js_dev_runtime/private/ddc_runtime/errors.dart 236:49  throw_
C:/b/s/w/ir/cache/builder/src/out/host_debug/dart-sdk/lib/_internal/js_dev_runtime/private/ddc_runtime/errors.dart 29:3    assertFailed
packages/flutter/src/widgets/widget_span.dart 105:22                                                                       build
packages/flutter/src/painting/text_span.dart 252:14                                                                        build
packages/flutter/src/painting/text_painter.dart 569:7                                                                      layout
...
The following RenderObject was being processed when the exception was fired: RenderEditable#a1504 relayoutBoundary=up73 NEEDS-LAYOUT NEEDS-PAINT NEEDS-COMPOSITING-BITS-UPDATE
RenderObject: RenderEditable#a1504 relayoutBoundary=up73 NEEDS-LAYOUT NEEDS-PAINT NEEDS-COMPOSITING-BITS-UPDATE
    parentData: <none> (can use size)
    constraints: BoxConstraints(w=1335.8, 0.0<=h<=Infinity)
    size: MISSING
    cursorColor: Color(0x00f46b45)
    showCursor: ValueNotifier<bool>#47e2f(true)
    maxLines: null
    minLines: 1
    selectionColor: Color(0x662196f3)
    textScaleFactor: 1.0
    locale: en_US
    selection: TextSelection(baseOffset: -1, extentOffset: -1, affinity: TextAffinity.downstream, isDirectional: false)
    offset: ScrollPositionWithSingleContext#4e4f3(offset: 0.0, range: null..null, viewport: null, ScrollableState, ClampingScrollPhysics -> RangeMaintainingScrollPhysics, IdleScrollActivity#e2324, ScrollDirection.idle)
    text: TextSpan
        debugLabel: (englishLike subhead 2014).merge((blackRedmond subtitle1).apply)
        inherit: false
        color: Color(0xdd000000)
        family: Noto
        size: 16.0
        weight: 400
        baseline: alphabetic
Assertion failed:
..\…\rendering\box.dart:1930
hasSize
"RenderBox was not laid out: RenderSemanticsAnnotations#17089 relayoutBoundary=up69 NEEDS-PAINT NEEDS-COMPOSITING-BITS-UPDATE"

The relevant error-causing widget was
TextField-[GlobalKey#d0c03 rectoinputText]
lib\…\flashCardCreate_tile\flashcardcreate_tile.dart:1972

@Paul-cbt Did you manage to find a solution for this problem?
Edit: It turns out i was using the wrong channel. Using master channel "fixes" this

@justin-m-lacy
Copy link

Hello! In what version is this api available? I am currently using 2.2.1, i was reading through TextEditingController
and i saw this method TextSpan buildTextSpan({required BuildContext context, TextStyle? style , required bool withComposing}) {..}, in the comments it says we should override this if we want to provide customized text.

I wrote this function

  @override
  TextSpan buildTextSpan({required BuildContext context, TextStyle? style, required bool withComposing}) {
    final atIndex = text.indexOf('@');
    var spans = <InlineSpan>[];

    if (atIndex != -1) {
      spans.add(TextSpan(text: text.substring(0, atIndex)));
      spans.add(
        WidgetSpan(
          alignment: PlaceholderAlignment.middle,
          child: Card(
            child: Padding(
              padding: const EdgeInsets.all(4.0),
              child: Text('@'),
            ),
          ),
        ),
      );
      spans.add(TextSpan(text: text.substring(1 + atIndex)));
    } else {
      spans.add(TextSpan(text: text));
    }

    return TextSpan(
      children: spans,
    );
  }

What is does, it replaces the @ symbol with a widget, but this crashes with this assertion
'package:flutter/src/widgets/widget_span.dart': Failed assertion: line 105 pos 12: 'dimensions != null': is not true.

I probably dont understand how it should be done, is there any guide or its not available yet? thanks!

I seem to be having this same problem - and most likely for the same reason. I'm using custom widgets for tagged elements in input text but WidgetSpan appears to break TextField because of the dimensions issue.

@Arrowsome
Copy link

Arrowsome commented Oct 15, 2021

Any update on this issue?
I Wanted to draw a simple rounded background color behind my text and it seems possible using WidgetSpan (or if Paint class supported rounded corners in fill style, which doesn't).
It's 2021 and I can't implement an effect from 2014 in Flutter!

@HansMuller HansMuller added the c: proposal A detailed proposal for a change to Flutter label Nov 11, 2021
@wrteam-priyansh
Copy link

wrteam-priyansh commented Nov 17, 2021

I'm trying to implement it by myself and got something "kind of working".

This is the piece of code I put inside the "buildTextSpan" method of TextEditingController : Capture d’écran 2021-03-20 à 14 48 21

And what it looks like in action :

WidgetSpan_Offset_Problem.mov
As you can see there's an offset problem of two characters because of the two WidgetSpans added before the TextSpan. There's also the problem of the cursor not adapting its height to the WidgetSpan. I just did what @GaryQian said above and took a look at RenderParagraph and Copy-Pasted some code inside RenderEditable (as well as some minor modifications inside EditableText). I'll try and read those file and see if I can solve those problems.

I'm also building a RichTextField using the default TextField Widget Flutter is offering and it looks kind of promising, here's a peek :

RichTextField_Peek.mov
You'll be able to customize the toolbar or provide your own and create as many styles as you want.

Hello @Teio07, can you please share some initial building blocks to build RichTextField with some basic functionality?
Thanks

@hwasoocho
Copy link

Any progress on this issue?

@Renzo-Olivares
Copy link
Contributor

Renzo-Olivares commented Mar 17, 2022

I made a simple example to show that WidgetSpans render inside of a TextField inline with other text. Core support for this was added in #83537 . Is this what this issue is asking for? If not please explain further.

import 'package:flutter/material.dart';

void main() {
  runApp(const MyApp());
}

class MyApp extends StatelessWidget {
  const MyApp({Key? key}) : super(key: key);

  // This widget is the root of your application.
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Flutter Demo',
      theme: ThemeData(
        primarySwatch: Colors.blue,
      ),
      home: const MyHomePage(title: 'Flutter Demo Home Page'),
    );
  }
}

class MyHomePage extends StatefulWidget {
  const MyHomePage({Key? key, required this.title}) : super(key: key);

  final String title;

  @override
  State<MyHomePage> createState() => _MyHomePageState();
}

class _MyHomePageState extends State<MyHomePage> {
  final WidgetSpanTextEditingController _controller =
      WidgetSpanTextEditingController(
          text: 'The quick brown fox jumps over the lazy \uffff dog.');

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text(widget.title),
      ),
      body: Center(
        child: TextField(
          controller: _controller,
          maxLines: null,
        ),
      ),
    );
  }
}

class WidgetSpanTextEditingController extends TextEditingController {
  WidgetSpanTextEditingController({String? text})
      : super.fromValue(text == null
            ? TextEditingValue.empty
            : TextEditingValue(text: text));

  @override
  TextSpan buildTextSpan(
      {required BuildContext context,
      TextStyle? style,
      required bool withComposing}) {

    TextRange? matchedRange;

    if (text.contains('\uffff')) {
      matchedRange = _findMatchedRange(text);
    }

    if (matchedRange != null) {
      return TextSpan(
        children: [
          TextSpan(text: matchedRange.textBefore(text)),
          const WidgetSpan(child: FlutterLogo()),
          TextSpan(text: matchedRange.textAfter(text)),
        ],
        style: style,
      );
    }

    return TextSpan(text: text, style: style);
  }

  TextRange _findMatchedRange(String text) {
    final RegExp matchPattern = RegExp(RegExp.escape('\uffff'));
    late TextRange matchedRange;
    
    for (final Match match in matchPattern.allMatches(text)) {
      matchedRange = TextRange(start: match.start, end: match.end);
    }

    return matchedRange;
  }
}

Screen Shot 2022-03-17 at 1 33 53 PM

@Renzo-Olivares Renzo-Olivares added the waiting for customer response The Flutter team cannot make further progress on this issue until the original reporter responds label Mar 17, 2022
@yohom
Copy link

yohom commented Mar 18, 2022

I made a simple example to show that WidgetSpans render inside of a TextField inline with other text. Core support for this was added in #83537 . Is this what this issue is asking for? If not please explain further.

import 'package:flutter/material.dart';

void main() {
  runApp(const MyApp());
}

class MyApp extends StatelessWidget {
  const MyApp({Key? key}) : super(key: key);

  // This widget is the root of your application.
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Flutter Demo',
      theme: ThemeData(
        primarySwatch: Colors.blue,
      ),
      home: const MyHomePage(title: 'Flutter Demo Home Page'),
    );
  }
}

class MyHomePage extends StatefulWidget {
  const MyHomePage({Key? key, required this.title}) : super(key: key);

  final String title;

  @override
  State<MyHomePage> createState() => _MyHomePageState();
}

class _MyHomePageState extends State<MyHomePage> {
  final WidgetSpanTextEditingController _controller =
      WidgetSpanTextEditingController(
          text: 'The quick brown fox jumps over the lazy \uffff dog.');

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text(widget.title),
      ),
      body: Center(
        child: TextField(
          controller: _controller,
          maxLines: null,
        ),
      ),
    );
  }
}

class WidgetSpanTextEditingController extends TextEditingController {
  WidgetSpanTextEditingController({String? text})
      : super.fromValue(text == null
            ? TextEditingValue.empty
            : TextEditingValue(text: text));

  @override
  TextSpan buildTextSpan(
      {required BuildContext context,
      TextStyle? style,
      required bool withComposing}) {

    TextRange? matchedRange;

    if (text.contains('\uffff')) {
      matchedRange = _findMatchedRange(text);
    }

    if (matchedRange != null) {
      return TextSpan(
        children: [
          TextSpan(text: matchedRange.textBefore(text)),
          const WidgetSpan(child: FlutterLogo()),
          TextSpan(text: matchedRange.textAfter(text)),
        ],
        style: style,
      );
    }

    return TextSpan(text: text, style: style);
  }

  TextRange _findMatchedRange(String text) {
    final RegExp matchPattern = RegExp(RegExp.escape('\uffff'));
    late TextRange matchedRange;
    
    for (final Match match in matchPattern.allMatches(text)) {
      matchedRange = TextRange(start: match.start, end: match.end);
    }

    return matchedRange;
  }
}
Screen Shot 2022-03-17 at 1 33 53 PM

@Renzo-Olivares
The buildTextSpan renders WidgetSpan successfully in a TextField, but the cursor can not locate to the last position. When you try to move the cursor to the last position, the cursor jumps to the first position.
My flutter doctor:

Doctor summary (to see all details, run flutter doctor -v):
[✓] Flutter (Channel stable, 2.10.3, on macOS 12.2.1 21D62 darwin-arm, locale en-CN)
[✓] Android toolchain - develop for Android devices (Android SDK version 31.0.0)
[✓] Xcode - develop for iOS and macOS (Xcode 13.3)
[✓] Chrome - develop for the web
[✓] Android Studio (version 2021.1)
[✓] IntelliJ IDEA Ultimate Edition (version 2021.3.2)
[✓] IntelliJ IDEA Community Edition (version 2021.2.4)
[✓] IntelliJ IDEA Ultimate Edition (version 2021.2.4)
[✓] VS Code (version 1.65.2)
Screenrecorder-2022-03-18-09-00-36-63.mp4

@Renzo-Olivares
Copy link
Contributor

Renzo-Olivares commented Mar 18, 2022

@yohom thanks for trying it out. I was able to reproduce your issue on stable as well. It is fixed on the master branch (video below).

screen-20220318-130824.mp4

I'll close this for now since core support for a WidgetSpan in a TextField/RenderEditable is there. If there are more specific issues with WidgetSpan inside of a TextField I encourage anyone to open a more targeted issue.

@github-actions
Copy link

github-actions bot commented Apr 1, 2022

This thread has been automatically locked since there has not been any recent activity after it was closed. If you are still experiencing a similar issue, please open a new bug, including the output of flutter doctor -v and a minimal reproduction of the issue.

@github-actions github-actions bot locked as resolved and limited conversation to collaborators Apr 1, 2022
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
a: text input Entering text in a text field or keyboard related problems c: new feature Nothing broken; request for a new capability c: proposal A detailed proposal for a change to Flutter f: material design flutter/packages/flutter/material repository. framework flutter/packages/flutter repository. See also f: labels. P1 High-priority issues at the top of the work list waiting for customer response The Flutter team cannot make further progress on this issue until the original reporter responds
Projects
None yet
Development

No branches or pull requests