Flutter_widget_from_html: TextTheme support instead of TextStyle

Created on 19 May 2020  路  5Comments  路  Source: daohoangson/flutter_widget_from_html

This is by far the best html viewer widget that I have tried. It would be great tho if there was support for TextTheme.

For example my app uses the following TextTheme:

headline1: GoogleFonts.raleway(
fontSize: 24,
fontWeight: FontWeight.w600,
color: Colors.blue,
),
headline2: GoogleFonts.raleway(
fontSize: 20,
fontWeight: FontWeight.w600,
color: Colors.blue.shade900,
),
headline3: GoogleFonts.raleway(
fontSize: 18,
fontWeight: FontWeight.w500,
color: Colors.white30,
),
headline4: GoogleFonts.raleway(
fontSize: 16,
fontWeight: FontWeight.w400,
color: Colors.white70,
),
headline5: GoogleFonts.raleway(
fontSize: 14,
fontWeight: FontWeight.w400,
color: Colors.white,
),
headline6: GoogleFonts.raleway(
fontSize: 12,
fontWeight: FontWeight.w500,
color: Colors.white60,
),
subtitle1: GoogleFonts.montserrat(
fontSize: 16,
fontWeight: FontWeight.w400,
letterSpacing: 0.15,
color: Colors.white,
),
subtitle2: GoogleFonts.montserrat(
fontSize: 14,
fontWeight: FontWeight.w500,
letterSpacing: 0.1,
color: Colors.white,
),
bodyText1: GoogleFonts.sourceSansPro(
fontSize: 16,
fontWeight: FontWeight.w400,
letterSpacing: 0.5,
color: Colors.white70),
bodyText2: GoogleFonts.sourceSansPro(
fontSize: 14,
fontWeight: FontWeight.w400,
letterSpacing: 0.3,
color: Colors.white70),

It would be nice if the following elements would be displayed like:

<h1> headline1
<h2> headline2
<h3> headline3
<h4> headline4
<h5> headline5
<h6> headline6
<p> bodyText1

Or to be able to give your own styles to the HtmlWidget.

I'm kinda new to flutter so when I looked in the source code I couldn't figure out how to do this. Is there support for this available?

question

Most helpful comment

With the latest 0.5 pre-release (version 0.5.0-rc.2020081901), it's now quite easy to apply text theme with custom WidgetFactory, something like this:

test.dart

class Test extends StatelessWidget {
  @override
  Widget build(BuildContext context) => Scaffold(
        appBar: AppBar(title: Text('Issue 187')),
        body: SingleChildScrollView(
          child: HtmlWidget(
            kHtml,
            factoryBuilder: () => _WidgetFactory(),
          ),
        ),
      );
}

const kHtml = '''
<h1>Heading 1</h1>
<h2>Heading 2</h2>
<h3>Heading 3</h3>
<h4>Heading 4</h4>
<h5>Heading 5</h5>
<h6>Heading 6</h6>
<p>A paragraph with <strong>strong</strong> <em>emphasized</em> text.</p>

<div>Just a DIV.</div>
''';

class _WidgetFactory extends WidgetFactory {
  @override
  void parse(BuildMetadata meta) {
    switch (meta.element.localName) {
      case 'h1':
      case 'h2':
      case 'h3':
      case 'h4':
      case 'h5':
      case 'h6':
      case 'p':
        meta
          ..['display'] = 'block'
          ..['margin'] = '0.5em 0'
          ..tsb(_applyTextTheme, meta.element.localName);

        // returning here without calling super will disable the default styling
        // for these tags completely.
        return;
    }

    super.parse(meta);
  }

  static TextStyleHtml _applyTextTheme(TextStyleHtml tsh, String tag) {
    final textTheme = tsh.getDependency<ThemeData>().textTheme;
    TextStyle style;
    switch (tag) {
      case 'h1':
        style = textTheme.headline1;
        break;
      case 'h2':
        style = textTheme.headline2;
        break;
      case 'h3':
        style = textTheme.headline3;
        break;
      case 'h4':
        style = textTheme.headline4;
        break;
      case 'h5':
        style = textTheme.headline5;
        break;
      case 'h6':
        style = textTheme.headline6;
        break;
      case 'p':
        style = textTheme.bodyText1;
        break;
    }

    if (style != null) {
      tsh = tsh.copyWith(style: style);
    }

    return tsh;
  }
}

It'll look like this:

All 5 comments

These text theme have just been added recently (Flutter 1.17 I think) so they weren't available at when this package was first developed. Instead this package relies on DefaultTextStyle and multiply font sizes to make them similar to browser's values.

You should be able to change the base font with DefaultTextStyle. The font size will be calculated automatically.

With the latest 0.5 pre-release (version 0.5.0-rc.2020081901), it's now quite easy to apply text theme with custom WidgetFactory, something like this:

test.dart

class Test extends StatelessWidget {
  @override
  Widget build(BuildContext context) => Scaffold(
        appBar: AppBar(title: Text('Issue 187')),
        body: SingleChildScrollView(
          child: HtmlWidget(
            kHtml,
            factoryBuilder: () => _WidgetFactory(),
          ),
        ),
      );
}

const kHtml = '''
<h1>Heading 1</h1>
<h2>Heading 2</h2>
<h3>Heading 3</h3>
<h4>Heading 4</h4>
<h5>Heading 5</h5>
<h6>Heading 6</h6>
<p>A paragraph with <strong>strong</strong> <em>emphasized</em> text.</p>

<div>Just a DIV.</div>
''';

class _WidgetFactory extends WidgetFactory {
  @override
  void parse(BuildMetadata meta) {
    switch (meta.element.localName) {
      case 'h1':
      case 'h2':
      case 'h3':
      case 'h4':
      case 'h5':
      case 'h6':
      case 'p':
        meta
          ..['display'] = 'block'
          ..['margin'] = '0.5em 0'
          ..tsb(_applyTextTheme, meta.element.localName);

        // returning here without calling super will disable the default styling
        // for these tags completely.
        return;
    }

    super.parse(meta);
  }

  static TextStyleHtml _applyTextTheme(TextStyleHtml tsh, String tag) {
    final textTheme = tsh.getDependency<ThemeData>().textTheme;
    TextStyle style;
    switch (tag) {
      case 'h1':
        style = textTheme.headline1;
        break;
      case 'h2':
        style = textTheme.headline2;
        break;
      case 'h3':
        style = textTheme.headline3;
        break;
      case 'h4':
        style = textTheme.headline4;
        break;
      case 'h5':
        style = textTheme.headline5;
        break;
      case 'h6':
        style = textTheme.headline6;
        break;
      case 'p':
        style = textTheme.bodyText1;
        break;
    }

    if (style != null) {
      tsh = tsh.copyWith(style: style);
    }

    return tsh;
  }
}

It'll look like this:

I just tested it. And it is amazing!!

Do you think it is stable enough for a production release?

This seems like using a text theme would always be the way to go now. Can we reopen this?

This issue is quite old and the original issue has been solved. Let's open a new one with your specific use case. I think it's better that way.

Was this page helpful?
0 / 5 - 0 ratings

Related issues

yoush97 picture yoush97  路  6Comments

forever84721 picture forever84721  路  4Comments

SoFo12 picture SoFo12  路  4Comments

yerzhant picture yerzhant  路  7Comments

red42 picture red42  路  4Comments