daohoangson / flutter_widget_from_html

Flutter package to render html as widgets that supports hyperlink, image, audio, video, iframe and many other tags.
https://pub.dev/packages/flutter_widget_from_html
MIT License
624 stars 229 forks source link

[Question] customWidgetBuilder builds text on newline #779

Closed kitsuniru closed 1 year ago

kitsuniru commented 2 years ago

Hi, I'm trying to make a custom style for links (a href) and edit the content a bit (element.text) - everything works perfectly, but the text is transferred to a new line if we use the Text widget, and it doesn't work to pass TextSpan as a widget

Tell me how to keep the order, but at the same time get access to element.text (and edit it)

I dare to assume that I need to write my own WidgetFactory, but I don't understand how to do it

daohoangson commented 2 years ago

If you don't control the HTML then this kind of customization needs your own WidgetFactory. I can provide some guidance if there are more information.

kitsuniru commented 2 years ago

If you don't control the HTML then this kind of customization needs your own WidgetFactory. I can provide some guidance if there are more information.

Thank you for your reply.

Here's i have code:

customWidgetBuilder: (element) {
                        if (element.localName == 'a') {
                          return Text(
                            element.text.substring(
                                element.text.indexOf(RegExp('[a-zA-Z0-9,.@#]')) + 1),
                            style: const TextStyle(
                                color: Colors.redAccent, fontWeight: FontWeight.bold),
                          );
                        }
                        return null;
                      }

But if i use this then matched link Text are transferred to the next line I want the text to change and be highlighted in red when the condition is met, without moving to a new line

galihuotui commented 1 year ago

Hello there, I also have the same case with the code below:

HtmlWidget(
    "<font color=\"#FF0000\">some html text, some html text some html text, some html text </font>" + "<img src=\"test_icon\"/>",
    customWidgetBuilder: (element) {
      if (element.attributes['src'] == 'test_icon') {
        return InkWell(
          onTap: () {

          },
          child: Container(
            width: 14,
            height: 14,
            child: Image.asset(
              "images/test_icon.png",
              fit: BoxFit.fill,
              width: 14,
              height: 14,
            ),
          ),
        );
      }
      return null;

    },
  )

When renders , the image widget will render in a new line below the html content, is there any solution to keep the icon at the end of the html content , no matter the html content is one line or more than one lines.

MarcinHradowicz commented 1 year ago

I have the same problem with customWidgetBuilder. The following should be rendered without new lines. image

But when I change this line image

then it looks fine image

Any idea how to solve that? 🤔

MarcinHradowicz commented 1 year ago

Ok I've managed to reach my goal with the use of FactoryWidget. Thanks to the example from this issue

class MentionsWidgetFactory extends WidgetFactory {
  MentionsWidgetFactory({
    required this.context,
    required this.htmlTextStyle,
  });

  final BuildContext context;
  final TextStyle htmlTextStyle;

  @override
  void parse(BuildMetadata meta) {
    final element = meta.element;
    if (element.attributes['class'] == 'mention') {
      final String dataDenotationChar = element.attributes['data-denotation-char'].toString();
      final String userSlug = element.attributes['data-slug'].toString();

      meta.register(BuildOp(
        onTree: (meta, tree) {
          WidgetBit.inline(
            tree.parent!,
            InkWell(
              onTap: () => context.push(ProfilePage.routeToPush(userSlug)),
              child: Text(
                dataDenotationChar + element.attributes['data-value'].toString(),
                style: htmlTextStyle.copyWith(
                  color: Theme.of(context).colorScheme.primary,
                  fontWeight: FontWeight.w700,
                ),
              ),
            ),
          ).insertBefore(tree);
          tree.detach();
        },
      ));

      return;
    }

    return super.parse(meta);
  }
}

and then pass it to HtmlWidget

HtmlWidget(
    widget.post.body,
    textStyle: htmlTextStyle,
    onTapUrl: (String url) async => openExternalUrl(url),
    factoryBuilder: () => MentionsWidgetFactory(context: context, htmlTextStyle: htmlTextStyle),
),
kitsuniru commented 1 year ago

since we have solution to this i'll close this issue thanks to @MarcinHradowicz