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

[flutter_markdown] "scrollController.position.maxScrollExtent" is not a fixed value #98813

Open
guchengxi1994 opened this issue Feb 20, 2022 · 9 comments
Labels
found in release: 2.10 Found to occur in 2.10 found in release: 2.11 Found to occur in 2.11 has reproducible steps The issue has been confirmed reproducible and is ready to work on p: flutter_markdown flutter/packages flutter_markdown P3 Issues that are less important to the Flutter project package flutter/packages repository. See also p: labels. team-ecosystem Owned by Ecosystem team triaged-ecosystem Triaged by Ecosystem team

Comments

@guchengxi1994
Copy link

guchengxi1994 commented Feb 20, 2022

I was using flutter_markdown in my app and i want to get the markdown height with a ScrollController, but the scrollController.position.maxScrollExtent is not a fixed value. Here are my codes:

code sample
import 'package:codind/entity/schedule.dart';
import 'package:codind/utils/utils.dart';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:flutter_i18n/flutter_i18n.dart';
import 'package:flutter_markdown/flutter_markdown.dart';
import 'package:url_launcher/url_launcher.dart';

enum DataFrom { net, asset, string, file }

// ignore: must_be_immutable
class BaseMarkdownPreviewPage extends StatefulWidget {
  BaseMarkdownPreviewPage(
      {Key? key, this.mdData, required this.from, this.tip, this.schedule})
      : super(key: key);
  final DataFrom from;
  String? mdData;
  String? tip;
  Schedule? schedule;

  @override
  State<BaseMarkdownPreviewPage> createState() =>
      _BaseMarkdownPreviewPageState();
}

class _BaseMarkdownPreviewPageState extends State<BaseMarkdownPreviewPage> {
  late String markdownData;
  // ignore: prefer_typing_uninitialized_variables
  var _loadDataFuture;

  ScrollController scrollController = ScrollController();
  GlobalKey<State<Markdown>> _globalKey = GlobalKey();

  @override
  void initState() {
    super.initState();
    if (widget.from == DataFrom.string) {
      _loadDataFuture = loadDataFromString();
    } else if (widget.from == DataFrom.asset) {
      _loadDataFuture = loadDataFromAsset();
    } else if (widget.from == DataFrom.net) {
      _loadDataFuture = justAMoment();
    } else {}

    scrollController.addListener(() {
      print("maxScrollExtent:" +
          scrollController.position.maxScrollExtent.toString());
      print("offset:" + scrollController.offset.toString());
    });

    WidgetsBinding.instance!.addPostFrameCallback((timeStamp) {
      print(CommonUtils.screenH());
      print(context.size?.height);
    });
  }

  justAMoment() async {
    await Future.delayed(const Duration(milliseconds: 1));
  }

  loadDataFromAsset() async {
    var _data = await rootBundle.loadString(widget.mdData!);
    setState(() {
      markdownData = _data;
    });
  }

  loadDataFromString() async {
    await Future.delayed(const Duration(milliseconds: 1)).then((value) {
      if (widget.mdData != null) {
        setState(() {
          markdownData = widget.mdData!;
        });
      } else {
        setState(() {
          markdownData = FlutterI18n.translate(context, "label.errorMdStr");
        });
      }
    });
  }

  @override
  void dispose() {
    scrollController.dispose();
    super.dispose();
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: null,
      // ignore: avoid_unnecessary_containers
      body: FutureBuilder(
        future: _loadDataFuture,
        builder: (context, snap) {
          if (snap.connectionState == ConnectionState.done) {
            if (widget.from != DataFrom.net) {
              return Markdown(
                key: _globalKey,
                controller: scrollController,
                data: markdownData,
                onTapLink: (text, href, title) async {
                  if (await canLaunch(href!)) {
                    await launch(href);
                  } else {
                    showToastMessage(
                        FlutterI18n.translate(context, "label.cannotLaunch"),
                        context);
                  }
                },
              );
            } else {
              return TextButton(
                  onPressed: () async {
                    if (await canLaunch(widget.mdData!)) {
                      await launch(widget.mdData!);
                    } else {
                      showToastMessage(
                          FlutterI18n.translate(context, "label.cannotLaunch"),
                          context);
                    }
                  },
                  child: Text(
                      FlutterI18n.translate(context, "label.clickToLaunch")));
            }
          } else {
            return Center(
              child: Text(FlutterI18n.translate(context, "label.loadingStr")),
            );
          }
        },
      ),
    );
  }
}

I add a listener in scrollercontroller to get the maxScrollExtent,but the result is not fixed.

code_find_05

@maheshmnj maheshmnj added the in triage Presently being triaged by the triage team label Feb 21, 2022
@maheshmnj
Copy link
Member

Hi @guchengxi1994, Thanks for filing the issue. Your code sample contains a lot of unknown/dependent variables I narrowed down your code sample by removing such variables and I could not reproduce the issue the maxScrollExtent was always a constant value. I verified this issue on stable 2.10.2 on Android Xiaomi k20 pro (Android 11).
Please check the below code sample and feel free to share an updated code sample that reproducess the issue along with the output of flutter doctor -v.

code sample
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:flutter_markdown/flutter_markdown.dart';

void main() => runApp(MyApp());

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return const MaterialApp(
      title: 'markdown sample',
      home: HomePage(),
    );
  }
}

class HomePage extends StatefulWidget {
  const HomePage({Key? key}) : super(key: key);

  @override
  _HomePageState createState() => _HomePageState();
}

class _HomePageState extends State<HomePage> {
  final controller = ScrollController();
  @override
  Widget build(BuildContext context) {
    return Material(
        child: BaseMarkdownPreviewPage(
      from: DataFrom.string,
      mdData: _notes,
    ));
  }
}

const String _notes = """
# Basic Markdown Demo
---
The Basic Markdown Demo shows the effect of the four Markdown extension sets
on formatting basic and extended Markdown tags.

## Overview
The Dart [markdown](https://pub.dev/packages/markdown) package parses Markdown
into HTML. The flutter_markdown package builds on this package using the
abstract syntax tree generated by the parser to make a tree of widgets instead
of HTML elements.
The markdown package supports the basic block and inline Markdown syntax
specified in the original Markdown implementation as well as a few Markdown
extensions. The markdown package uses extension sets to make extension
management easy. There are four pre-defined extension sets; none, Common Mark,
GitHub Flavored, and GitHub Web. The default extension set used by the
flutter_markdown package is GitHub Flavored.
The Basic Markdown Demo shows the effect each of the pre-defined extension sets
has on a test Markdown document with basic and extended Markdown tags. Use the
Extension Set dropdown menu to select an extension set and view the Markdown
widget's output.
## Comments
Since GitHub Flavored is the default extension set, it is the initial setting
Since GitHub Flavored is the default extension set, it is the initial setting
Since GitHub Flavored is the default extension set, it is the initial setting
Since GitHub Flavored is the default extension set, it is the initial setting
Since GitHub Flavored is the default extension set, it is the initial setting
Since GitHub Flavored is the default extension set, it is the initial setting
Since GitHub Flavored is the default extension set, it is the initial setting
Since GitHub Flavored is the default extension set, it is the initial setting
Since GitHub Flavored is the default extension set, it is the initial setting
Since GitHub Flavored is the default extension set, it is the initial setting
Since GitHub Flavored is the default extension set, it is the initial setting
Since GitHub Flavored is the default extension set, it is the initial setting
Since GitHub Flavored is the default extension set, it is the initial setting
Since GitHub Flavored is the default extension set, it is the initial setting
Since GitHub Flavored is the default extension set, it is the initial setting
Since GitHub Flavored is the default extension set, it is the initial setting
Since GitHub Flavored is the default extension set, it is the initial setting
Since GitHub Flavored is the default extension set, it is the initial setting
Since GitHub Flavored is the default extension set, it is the initial setting
Since GitHub Flavored is the default extension set, it is the initial setting
Since GitHub Flavored is the default extension set, it is the initial setting
Since GitHub Flavored is the default extension set, it is the initial setting
Since GitHub Flavored is the default extension set, it is the initial setting
Since GitHub Flavored is the default extension set, it is the initial setting
Since GitHub Flavored is the default extension set, it is the initial setting
Since GitHub Flavored is the default extension set, it is the initial setting
Since GitHub Flavored is the default extension set, it is the initial setting
Since GitHub Flavored is the default extension set, it is the initial setting
Since GitHub Flavored is the default extension set, it is the initial setting
Since GitHub Flavored is the default extension set, it is the initial setting
for the formatted Markdown view in the demo.


""";

enum DataFrom { net, asset, string, file }

// ignore: must_be_immutable
class BaseMarkdownPreviewPage extends StatefulWidget {
  BaseMarkdownPreviewPage({Key? key, this.mdData, required this.from})
      : super(key: key);
  final DataFrom from;
  String? mdData;

  @override
  State<BaseMarkdownPreviewPage> createState() =>
      _BaseMarkdownPreviewPageState();
}

class _BaseMarkdownPreviewPageState extends State<BaseMarkdownPreviewPage> {
  late String markdownData;
  // ignore: prefer_typing_uninitialized_variables
  var _loadDataFuture;

  ScrollController scrollController = ScrollController();
  GlobalKey<State<Markdown>> _globalKey = GlobalKey();

  @override
  void initState() {
    super.initState();
    if (widget.from == DataFrom.string) {
      _loadDataFuture = loadDataFromString();
    } else if (widget.from == DataFrom.asset) {
      _loadDataFuture = loadDataFromAsset();
    } else if (widget.from == DataFrom.net) {
      _loadDataFuture = justAMoment();
    } else {}

    scrollController.addListener(() {
      print("maxScrollExtent:" +
          scrollController.position.maxScrollExtent.toString());
      print("offset:" + scrollController.offset.toString());
    });

    WidgetsBinding.instance!.addPostFrameCallback((timeStamp) {
      print(context.size?.height);
    });
  }

  justAMoment() async {
    await Future.delayed(const Duration(milliseconds: 1));
  }

  loadDataFromAsset() async {
    var _data = await rootBundle.loadString(widget.mdData!);
    setState(() {
      markdownData = _data;
    });
  }

  loadDataFromString() async {
    await Future.delayed(const Duration(milliseconds: 1)).then((value) {
      if (widget.mdData != null) {
        setState(() {
          markdownData = widget.mdData!;
        });
      } else {
        setState(() {
          markdownData = _notes;
        });
      }
    });
  }

  @override
  void dispose() {
    scrollController.dispose();
    super.dispose();
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: null,
      // ignore: avoid_unnecessary_containers
      body: FutureBuilder(
        future: _loadDataFuture,
        builder: (context, snap) {
          if (snap.connectionState == ConnectionState.done) {
            if (widget.from != DataFrom.net) {
              return Markdown(
                key: _globalKey,
                controller: scrollController,
                data: markdownData,
                onTapLink: (text, href, title) async {},
              );
            } else {
              return TextButton(
                  onPressed: () async {}, child: const Text('click to launch'));
            }
          } else {
            return const Center(child: Text('label.loadingSt'));
          }
        },
      ),
    );
  }
}
logs
Launching lib/main.dart on Redmi K20 Pro in debug mode...
Warning: Mapping new ns http://schemas.android.com/repository/android/common/02 to old ns http://schemas.android.com/repository/android/common/01
Warning: Mapping new ns http://schemas.android.com/repository/android/generic/02 to old ns http://schemas.android.com/repository/android/generic/01
Warning: Mapping new ns http://schemas.android.com/sdk/android/repo/addon2/02 to old ns http://schemas.android.com/sdk/android/repo/addon2/01
Warning: Mapping new ns http://schemas.android.com/sdk/android/repo/repository2/02 to old ns http://schemas.android.com/sdk/android/repo/repository2/01
Warning: Mapping new ns http://schemas.android.com/sdk/android/repo/sys-img2/02 to old ns http://schemas.android.com/sdk/android/repo/sys-img2/01
Warning: Mapping new ns http://schemas.android.com/repository/android/common/02 to old ns http://schemas.android.com/repository/android/common/01
Warning: Mapping new ns http://schemas.android.com/repository/android/generic/02 to old ns http://schemas.android.com/repository/android/generic/01
Warning: Mapping new ns http://schemas.android.com/sdk/android/repo/addon2/02 to old ns http://schemas.android.com/sdk/android/repo/addon2/01
Warning: Mapping new ns http://schemas.android.com/sdk/android/repo/repository2/02 to old ns http://schemas.android.com/sdk/android/repo/repository2/01
Warning: Mapping new ns http://schemas.android.com/sdk/android/repo/sys-img2/02 to old ns http://schemas.android.com/sdk/android/repo/sys-img2/01
✓  Built build/app/outputs/flutter-apk/app-debug.apk.
Connecting to VM Service at ws://127.0.0.1:63569/bwR0mGkXMbw=/ws
I/flutter (32436): 803.6363636363636
I/ple.maps_sampl(32436): ProcessProfilingInfo new_methods=56 is saved saved_to_disk=1 resolve_classes_delay=8000
D/MIUIInput(32436): [MotionEvent] ViewRootImpl { action=ACTION_DOWN, id[0]=0, pointerCount=1, eventTime=53433579, downTime=53433579 } moveCount:0
W/MirrorManager(32436): this model don't Support
I/flutter (32436): maxScrollExtent:449.3636363636364
I/flutter (32436): offset:3.636363636363626
I/flutter (32436): maxScrollExtent:449.3636363636364
I/flutter (32436): offset:9.454545454545496
I/flutter (32436): maxScrollExtent:449.3636363636364
I/flutter (32436): offset:16.363636363636374
I/flutter (32436): maxScrollExtent:449.3636363636364
I/flutter (32436): offset:23.636363636363626
I/flutter (32436): maxScrollExtent:449.3636363636364
I/flutter (32436): offset:31.272727272727252
I/flutter (32436): maxScrollExtent:449.3636363636364
I/flutter (32436): offset:40.0
I/flutter (32436): maxScrollExtent:449.3636363636364
I/flutter (32436): offset:47.636363636363626
I/flutter (32436): maxScrollExtent:449.3636363636364
I/flutter (32436): offset:55.636363636363626
I/flutter (32436): maxScrollExtent:449.3636363636364
I/flutter (32436): offset:63.636363636363626
I/flutter (32436): maxScrollExtent:449.3636363636364
I/flutter (32436): offset:71.63636363636363
I/flutter (32436): maxScrollExtent:449.3636363636364
I/flutter (32436): offset:79.27272727272725
I/flutter (32436): maxScrollExtent:449.3636363636364
I/flutter (32436): offset:86.5454545454545
I/flutter (32436): maxScrollExtent:449.3636363636364
I/flutter (32436): offset:93.45454545454544
I/flutter (32436): maxScrollExtent:449.3636363636364
I/flutter (32436): offset:100.36363636363637
I/flutter (32436): maxScrollExtent:449.3636363636364
I/flutter (32436): offset:107.27272727272731
I/flutter (32436): maxScrollExtent:449.3636363636364
I/flutter (32436): offset:115.63636363636368
I/flutter (32436): maxScrollExtent:449.3636363636364
I/flutter (32436): offset:125.09090909090912
I/flutter (32436): maxScrollExtent:449.3636363636364
I/flutter (32436): offset:135.63636363636368
I/flutter (32436): maxScrollExtent:449.3636363636364
I/flutter (32436): offset:147.63636363636368
I/flutter (32436): maxScrollExtent:449.3636363636364
I/flutter (32436): offset:160.36363636363643
I/flutter (32436): maxScrollExtent:449.3636363636364
I/flutter (32436): offset:173.81818181818187
I/flutter (32436): maxScrollExtent:449.3636363636364
I/flutter (32436): offset:200.36363636363643
D/MIUIInput(32436): [MotionEvent] ViewRootImpl { action=ACTION_UP, id[0]=0, pointerCount=1, eventTime=53433830, downTime=53433579 } moveCount:22
I/flutter (32436): maxScrollExtent:449.3636363636364
I/flutter (32436): offset:262.2147313053421
I/flutter (32436): maxScrollExtent:449.3636363636364
I/flutter (32436): offset:291.29087483352697
I/flutter (32436): maxScrollExtent:449.3636363636364
I/flutter (32436): offset:345.993933707466
I/flutter (32436): maxScrollExtent:449.3636363636364
I/flutter (32436): offset:396.19118611166255
I/flutter (32436): maxScrollExtent:449.3636363636364
I/flutter (32436): offset:419.58634938022533
I/flutter (32436): maxScrollExtent:449.3636363636364
I/flutter (32436): offset:441.96277526440196
I/flutter (32436): maxScrollExtent:449.3636363636364
I/flutter (32436): offset:449.3636363636364
D/MIUIInput(32436): [MotionEvent] ViewRootImpl { action=ACTION_DOWN, id[0]=0, pointerCount=1, eventTime=53437193, downTime=53437193 } moveCount:0
I/flutter (32436): maxScrollExtent:449.3636363636364
I/flutter (32436): offset:449.0
I/flutter (32436): maxScrollExtent:449.3636363636364
I/flutter (32436): offset:447.90909090909093
I/flutter (32436): maxScrollExtent:449.3636363636364
I/flutter (32436): offset:446.0909090909091
I/flutter (32436): maxScrollExtent:449.3636363636364
I/flutter (32436): offset:443.54545454545456
I/flutter (32436): maxScrollExtent:449.3636363636364
I/flutter (32436): offset:440.6363636363636
I/flutter (32436): maxScrollExtent:449.3636363636364
I/flutter (32436): offset:438.09090909090907
I/flutter (32436): maxScrollExtent:449.3636363636364
I/flutter (32436): offset:435.18181818181813
I/flutter (32436): maxScrollExtent:449.3636363636364
I/flutter (32436): offset:432.99999999999994
I/flutter (32436): maxScrollExtent:449.3636363636364
I/flutter (32436): offset:431.18181818181813
I/flutter (32436): maxScrollExtent:449.3636363636364
I/flutter (32436): offset:429.3636363636363
I/flutter (32436): maxScrollExtent:449.3636363636364
I/flutter (32436): offset:427.18181818181813
I/flutter (32436): maxScrollExtent:449.3636363636364
I/flutter (32436): offset:425.3636363636363
I/flutter (32436): maxScrollExtent:449.3636363636364
I/flutter (32436): offset:423.18181818181813
I/flutter (32436): maxScrollExtent:449.3636363636364
I/flutter (32436): offset:421.3636363636363
I/flutter (32436): maxScrollExtent:449.3636363636364
I/flutter (32436): offset:419.5454545454545
I/flutter (32436): maxScrollExtent:449.3636363636364
I/flutter (32436): offset:417.7272727272727
I/flutter (32436): maxScrollExtent:449.3636363636364
I/flutter (32436): offset:416.6363636363636
I/flutter (32436): maxScrollExtent:449.3636363636364
I/flutter (32436): offset:415.9090909090909
I/flutter (32436): maxScrollExtent:449.3636363636364
I/flutter (32436): offset:415.5454545454545
I/flutter (32436): maxScrollExtent:449.3636363636364
I/flutter (32436): offset:415.18181818181813
I/flutter (32436): maxScrollExtent:449.3636363636364
I/flutter (32436): offset:414.81818181818176
I/flutter (32436): maxScrollExtent:449.3636363636364
I/flutter (32436): offset:414.4545454545454
I/flutter (32436): maxScrollExtent:449.3636363636364
I/flutter (32436): offset:414.090909090909
I/flutter (32436): maxScrollExtent:449.3636363636364
I/flutter (32436): offset:413.36363636363626
I/flutter (32436): maxScrollExtent:449.3636363636364
I/flutter (32436): offset:412.6363636363635
I/flutter (32436): maxScrollExtent:449.3636363636364
I/flutter (32436): offset:411.90909090909076
I/flutter (32436): maxScrollExtent:449.3636363636364
I/flutter (32436): offset:411.5454545454544
I/flutter (32436): maxScrollExtent:449.3636363636364
I/flutter (32436): offset:411.181818181818
I/flutter (32436): maxScrollExtent:449.3636363636364
I/flutter (32436): offset:410.81818181818164
I/flutter (32436): maxScrollExtent:449.3636363636364
I/flutter (32436): offset:410.45454545454527
I/flutter (32436): maxScrollExtent:449.3636363636364
I/flutter (32436): offset:410.0909090909089
I/flutter (32436): maxScrollExtent:449.3636363636364
I/flutter (32436): offset:409.7272727272725
I/flutter (32436): maxScrollExtent:449.3636363636364
I/flutter (32436): offset:409.36363636363615
I/flutter (32436): maxScrollExtent:449.3636363636364
I/flutter (32436): offset:408.6363636363634
I/flutter (32436): maxScrollExtent:449.3636363636364
I/flutter (32436): offset:407.90909090909065
I/flutter (32436): maxScrollExtent:449.3636363636364
I/flutter (32436): offset:407.1818181818179
I/flutter (32436): maxScrollExtent:449.3636363636364
I/flutter (32436): offset:406.81818181818153
I/flutter (32436): maxScrollExtent:449.3636363636364
I/flutter (32436): offset:406.0909090909088
I/flutter (32436): maxScrollExtent:449.3636363636364
I/flutter (32436): offset:405.7272727272724
I/flutter (32436): maxScrollExtent:449.3636363636364
I/flutter (32436): offset:405.36363636363603
I/flutter (32436): maxScrollExtent:449.3636363636364
I/flutter (32436): offset:404.99999999999966
I/flutter (32436): maxScrollExtent:449.3636363636364
I/flutter (32436): offset:404.6363636363633
I/flutter (32436): maxScrollExtent:449.3636363636364
I/flutter (32436): offset:404.2727272727269
I/flutter (32436): maxScrollExtent:449.3636363636364
I/flutter (32436): offset:403.90909090909054
I/flutter (32436): maxScrollExtent:449.3636363636364
I/flutter (32436): offset:403.54545454545416
I/flutter (32436): maxScrollExtent:449.3636363636364
I/flutter (32436): offset:403.1818181818178
I/flutter (32436): maxScrollExtent:449.3636363636364
I/flutter (32436): offset:402.8181818181814
I/flutter (32436): maxScrollExtent:449.3636363636364
I/flutter (32436): offset:402.45454545454504
I/flutter (32436): maxScrollExtent:449.3636363636364
I/flutter (32436): offset:402.09090909090867
I/flutter (32436): maxScrollExtent:449.3636363636364
I/flutter (32436): offset:402.45454545454504
I/flutter (32436): maxScrollExtent:449.3636363636364
I/flutter (32436): offset:402.8181818181814
I/flutter (32436): maxScrollExtent:449.3636363636364
I/flutter (32436): offset:403.1818181818178
I/flutter (32436): maxScrollExtent:449.3636363636364
I/flutter (32436): offset:403.54545454545416
I/flutter (32436): maxScrollExtent:449.3636363636364
I/flutter (32436): offset:404.2727272727269
I/flutter (32436): maxScrollExtent:449.3636363636364
I/flutter (32436): offset:404.99999999999966
I/flutter (32436): maxScrollExtent:449.3636363636364
I/flutter (32436): offset:406.0909090909087
I/flutter (32436): maxScrollExtent:449.3636363636364
I/flutter (32436): offset:407.54545454545416
I/flutter (32436): maxScrollExtent:449.3636363636364
I/flutter (32436): offset:408.9999999999996
I/flutter (32436): maxScrollExtent:449.3636363636364
I/flutter (32436): offset:411.1818181818178
I/flutter (32436): maxScrollExtent:449.3636363636364
I/flutter (32436): offset:413.363636363636
I/flutter (32436): maxScrollExtent:449.3636363636364
I/flutter (32436): offset:416.2727272727269
I/flutter (32436): maxScrollExtent:449.3636363636364
I/flutter (32436): offset:419.18181818181785
I/flutter (32436): maxScrollExtent:449.3636363636364
I/flutter (32436): offset:422.8181818181815
I/flutter (32436): maxScrollExtent:449.3636363636364
I/flutter (32436): offset:427.5454545454542
I/flutter (32436): maxScrollExtent:449.3636363636364
I/flutter (32436): offset:434.45454545454515
I/flutter (32436): maxScrollExtent:449.3636363636364
I/flutter (32436): offset:443.1818181818179
I/flutter (32436): maxScrollExtent:449.3636363636364
I/flutter (32436): offset:449.3636363636364
D/MIUIInput(32436): [MotionEvent] ViewRootImpl { action=ACTION_UP, id[0]=0, pointerCount=1, eventTime=53444459, downTime=53437193 } moveCount:75
D/MIUIInput(32436): [MotionEvent] ViewRootImpl { action=ACTION_DOWN, id[0]=0, pointerCount=1, eventTime=53444946, downTime=53444946 } moveCount:0
I/flutter (32436): maxScrollExtent:449.3636363636364
I/flutter (32436): offset:444.2727272727273
I/flutter (32436): maxScrollExtent:449.3636363636364
I/flutter (32436): offset:435.54545454545456
I/flutter (32436): maxScrollExtent:449.3636363636364
I/flutter (32436): offset:425.0
I/flutter (32436): maxScrollExtent:449.3636363636364
I/flutter (32436): offset:413.0
I/flutter (32436): maxScrollExtent:449.3636363636364
I/flutter (32436): offset:398.8181818181818
I/flutter (32436): maxScrollExtent:449.3636363636364
I/flutter (32436): offset:385.3636363636364
I/flutter (32436): maxScrollExtent:449.3636363636364
I/flutter (32436): offset:370.0909090909091
I/flutter (32436): maxScrollExtent:449.3636363636364
I/flutter (32436): offset:354.4545454545455
I/flutter (32436): maxScrollExtent:449.3636363636364
I/flutter (32436): offset:338.4545454545455
I/flutter (32436): maxScrollExtent:449.3636363636364
I/flutter (32436): offset:323.54545454545456
I/flutter (32436): maxScrollExtent:449.3636363636364
I/flutter (32436): offset:308.6363636363636
I/flutter (32436): maxScrollExtent:449.3636363636364
I/flutter (32436): offset:294.4545454545455
I/flutter (32436): maxScrollExtent:449.3636363636364
I/flutter (32436): offset:281.3636363636364
I/flutter (32436): maxScrollExtent:449.3636363636364
I/flutter (32436): offset:274.0909090909091
D/MIUIInput(32436): [MotionEvent] ViewRootImpl { action=ACTION_UP, id[0]=0, pointerCount=1, eventTime=53445114, downTime=53444946 } moveCount:14
I/flutter (32436): maxScrollExtent:449.3636363636364
I/flutter (32436): offset:245.57484046700773
I/flutter (32436): maxScrollExtent:449.3636363636364
I/flutter (32436): offset:218.42291331069964
I/flutter (32436): maxScrollExtent:449.3636363636364
I/flutter (32436): offset:192.38216372777106
I/flutter (32436): maxScrollExtent:449.3636363636364
I/flutter (32436): offset:167.53182057752718
I/flutter (32436): maxScrollExtent:449.3636363636364
I/flutter (32436): offset:143.7929562522336
I/flutter (32436): maxScrollExtent:449.3636363636364
I/flutter (32436): offset:121.0488044278045
I/flutter (32436): maxScrollExtent:449.3636363636364
I/flutter (32436): offset:99.50868650250464
I/flutter (32436): maxScrollExtent:449.3636363636364
I/flutter (32436): offset:78.937715139278
I/flutter (32436): maxScrollExtent:449.3636363636364
I/flutter (32436): offset:59.399255883825646
I/flutter (32436): maxScrollExtent:449.3636363636364
I/flutter (32436): offset:40.82744385812788
I/flutter (32436): maxScrollExtent:449.3636363636364
I/flutter (32436): offset:23.25403854677279
I/flutter (32436): maxScrollExtent:449.3636363636364
I/flutter (32436): offset:6.5597673707888475
I/flutter (32436): maxScrollExtent:449.3636363636364
I/flutter (32436): offset:0.0
D/MIUIInput(32436): [MotionEvent] ViewRootImpl { action=ACTION_DOWN, id[0]=0, pointerCount=1, eventTime=53445669, downTime=53445669 } moveCount:0
I/flutter (32436): maxScrollExtent:449.3636363636364
I/flutter (32436): offset:7.272727272727252
I/flutter (32436): maxScrollExtent:449.3636363636364
I/flutter (32436): offset:17.818181818181756
I/flutter (32436): maxScrollExtent:449.3636363636364
I/flutter (32436): offset:28.36363636363626
I/flutter (32436): maxScrollExtent:449.3636363636364
I/flutter (32436): offset:37.45454545454538
I/flutter (32436): maxScrollExtent:449.3636363636364
I/flutter (32436): offset:49.09090909090901
I/flutter (32436): maxScrollExtent:449.3636363636364
I/flutter (32436): offset:61.45454545454538
I/flutter (32436): maxScrollExtent:449.3636363636364
I/flutter (32436): offset:74.90909090909088
I/flutter (32436): maxScrollExtent:449.3636363636364
I/flutter (32436): offset:88.36363636363632
I/flutter (32436): maxScrollExtent:449.3636363636364
I/flutter (32436): offset:102.90909090909088
I/flutter (32436): maxScrollExtent:449.3636363636364
I/flutter (32436): offset:118.18181818181813
I/flutter (32436): maxScrollExtent:449.3636363636364
I/flutter (32436): offset:134.18181818181813
I/flutter (32436): maxScrollExtent:449.3636363636364
I/flutter (32436): offset:150.90909090909088
I/flutter (32436): maxScrollExtent:449.3636363636364
I/flutter (32436): offset:167.63636363636363
I/flutter (32436): maxScrollExtent:449.3636363636364
I/flutter (32436): offset:201.09090909090907
D/MIUIInput(32436): [MotionEvent] ViewRootImpl { action=ACTION_UP, id[0]=0, pointerCount=1, eventTime=53445811, downTime=53445669 } moveCount:14
I/flutter (32436): maxScrollExtent:449.3636363636364
I/flutter (32436): offset:242.353588022128
I/flutter (32436): maxScrollExtent:449.3636363636364
I/flutter (32436): offset:282.2724087867647
I/flutter (32436): maxScrollExtent:449.3636363636364
I/flutter (32436): offset:320.85525387108225
I/flutter (32436): maxScrollExtent:449.3636363636364
I/flutter (32436): offset:358.1408520686906
I/flutter (32436): maxScrollExtent:449.3636363636364
I/flutter (32436): offset:394.1446558249212
I/flutter (32436): maxScrollExtent:449.3636363636364
I/flutter (32436): offset:428.95130485093625
I/flutter (32436): maxScrollExtent:449.3636363636364
I/flutter (32436): offset:449.3636363636364
D/MIUIInput(32436): [MotionEvent] ViewRootImpl { action=ACTION_DOWN, id[0]=0, pointerCount=1, eventTime=53446628, downTime=53446628 } moveCount:0
I/flutter (32436): maxScrollExtent:449.3636363636364
I/flutter (32436): offset:443.1818181818182
I/flutter (32436): maxScrollExtent:449.3636363636364
I/flutter (32436): offset:433.3636363636364
I/flutter (32436): maxScrollExtent:449.3636363636364
I/flutter (32436): offset:422.0909090909091
I/flutter (32436): maxScrollExtent:449.3636363636364
I/flutter (32436): offset:409.72727272727275
I/flutter (32436): maxScrollExtent:449.3636363636364
I/flutter (32436): offset:391.90909090909093
I/flutter (32436): maxScrollExtent:449.3636363636364
I/flutter (32436): offset:370.81818181818187
I/flutter (32436): maxScrollExtent:449.3636363636364
I/flutter (32436): offset:346.4545454545455
I/flutter (32436): maxScrollExtent:449.3636363636364
I/flutter (32436): offset:321.00000000000006
I/flutter (32436): maxScrollExtent:449.3636363636364
I/flutter (32436): offset:270.45454545454555
D/MIUIInput(32436): [MotionEvent] ViewRootImpl { action=ACTION_UP, id[0]=0, pointerCount=1, eventTime=53446728, downTime=53446628 } moveCount:9
I/flutter (32436): maxScrollExtent:449.3636363636364
I/flutter (32436): offset:201.91766105043683
I/flutter (32436): maxScrollExtent:449.3636363636364
I/flutter (32436): offset:134.87594619340476
I/flutter (32436): maxScrollExtent:449.3636363636364
I/flutter (32436): offset:69.29409443692708
I/flutter (32436): maxScrollExtent:449.3636363636364
I/flutter (32436): offset:5.207235330294907
I/flutter (32436): maxScrollExtent:449.3636363636364
I/flutter (32436): offset:0.0
D/MIUIInput(32436): [MotionEvent] ViewRootImpl { action=ACTION_DOWN, id[0]=0, pointerCount=1, eventTime=53447316, downTime=53447316 } moveCount:0
I/flutter (32436): maxScrollExtent:449.3636363636364
I/flutter (32436): offset:9.090909090909122
I/flutter (32436): maxScrollExtent:449.3636363636364
I/flutter (32436): offset:22.545454545454618
I/flutter (32436): maxScrollExtent:449.3636363636364
I/flutter (32436): offset:36.36363636363649
I/flutter (32436): maxScrollExtent:449.3636363636364
I/flutter (32436): offset:49.090909090909236
I/flutter (32436): maxScrollExtent:449.3636363636364
I/flutter (32436): offset:65.81818181818198
I/flutter (32436): maxScrollExtent:449.3636363636364
I/flutter (32436): offset:84.36363636363649
I/flutter (32436): maxScrollExtent:449.3636363636364
I/flutter (32436): offset:105.09090909090924
I/flutter (32436): maxScrollExtent:449.3636363636364
I/flutter (32436): offset:128.00000000000017
I/flutter (32436): maxScrollExtent:449.3636363636364
I/flutter (32436): offset:151.6363636363638
I/flutter (32436): maxScrollExtent:449.3636363636364
I/flutter (32436): offset:200.36363636363654
D/MIUIInput(32436): [MotionEvent] ViewRootImpl { action=ACTION_UP, id[0]=0, pointerCount=1, eventTime=53447425, downTime=53447316 } moveCount:10
I/flutter (32436): maxScrollExtent:449.3636363636364
I/flutter (32436): offset:263.2617751556819
I/flutter (32436): maxScrollExtent:449.3636363636364
I/flutter (32436): offset:324.7187600384034
I/flutter (32436): maxScrollExtent:449.3636363636364
I/flutter (32436): offset:384.73186535749915
I/flutter (32436): maxScrollExtent:449.3636363636364
I/flutter (32436): offset:443.2478541308974
I/flutter (32436): maxScrollExtent:449.3636363636364
I/flutter (32436): offset:449.3636363636364
D/MIUIInput(32436): [MotionEvent] ViewRootImpl { action=ACTION_DOWN, id[0]=0, pointerCount=1, eventTime=53450232, downTime=53450232 } moveCount:0
D/MIUIInput(32436): [MotionEvent] ViewRootImpl { action=ACTION_UP, id[0]=0, pointerCount=1, eventTime=53450348, downTime=53450232 } moveCount:11

flutter doctor -v
[✓] Flutter (Channel stable, 2.10.2, on macOS 12.1 21C52 darwin-arm, locale en-GB)
    • Flutter version 2.10.2 at /Users/mahesh/Documents/flutter
    • Upstream repository https://github.com/flutter/flutter.git
    • Framework revision 097d3313d8 (2 days ago), 2022-02-18 19:33:08 -0600
    • Engine revision a83ed0e5e3
    • Dart version 2.16.1
    • DevTools version 2.9.2

[✓] Android toolchain - develop for Android devices (Android SDK version 31.0.0)
    • Android SDK at /Users/mahesh/Library/Android/sdk
    • Platform android-31, build-tools 31.0.0
    • ANDROID_HOME = /Users/mahesh/Library/Android/sdk
    • Java binary at: /Applications/Android Studio.app/Contents/jre/jdk/Contents/Home/bin/java
    • Java version OpenJDK Runtime Environment (build 11.0.8+10-b944.6916264)
    • All Android licenses accepted.

[✓] Xcode - develop for iOS and macOS (Xcode 13.2.1)
    • Xcode at /Applications/Xcode.app/Contents/Developer
    • CocoaPods version 1.10.2

[✓] Chrome - develop for the web
    • Chrome at /Applications/Google Chrome.app/Contents/MacOS/Google Chrome

[✓] Android Studio (version 4.2)
    • Android Studio at /Applications/Android Studio.app/Contents
    • Flutter plugin can be installed from:
      🔨 https://plugins.jetbrains.com/plugin/9212-flutter
    • Dart plugin can be installed from:
      🔨 https://plugins.jetbrains.com/plugin/6351-dart
    • Java version OpenJDK Runtime Environment (build 11.0.8+10-b944.6916264)

[✓] IntelliJ IDEA Community Edition (version 2021.2.1)
    • IntelliJ at /Applications/IntelliJ IDEA CE.app
    • Flutter plugin version 61.2.4
    • Dart plugin version 212.5080.8

[✓] VS Code (version 1.63.2)
    • VS Code at /Applications/Visual Studio Code.app/Contents
    • Flutter extension version 3.34.0

[✓] Connected device (3 available)
    • Redmi K20 Pro (mobile) • 192.168.1.2:5555 • android-arm64  • Android 11 (API 30)
    • macOS (desktop)        • macos            • darwin-arm64   • macOS 12.1 21C52 darwin-arm
    • Chrome (web)           • chrome           • web-javascript • Google Chrome 98.0.4758.102

[✓] HTTP Host Availability
    • All required HTTP hosts are available

• No issues found!

@maheshmnj maheshmnj added the waiting for customer response The Flutter team cannot make further progress on this issue until the original reporter responds label Feb 21, 2022
@maheshmnj maheshmnj changed the title "scrollController.position.maxScrollExtent" is not a fixed value [flutter_markdown] "scrollController.position.maxScrollExtent" is not a fixed value Feb 21, 2022
@guchengxi1994
Copy link
Author

I copied your code and it worked fine, then I made more tests .
Once i add these markdown signs in the markdown string, the value is not a constant.

***
# Title 1
## Title 2
### Title 3
#### Title 4
##### Title 5
###### Title 6
***

code_find_006

code_find_007

I think the issue may be related to markdown rendener or something else. My flutter_markdown version is 0.6.9 and here are my flutter doctor infomation.

Doctor summary (to see all details, run flutter doctor -v):
[√] Flutter (Channel dev, 2.10.0-0.3.pre, on Microsoft Windows [Version 10.0.19043.1526], locale zh-CN)
[X] Android toolchain - develop for Android devices
    X Unable to locate Android SDK.
      Install Android Studio from: https://developer.android.com/studio/index.html
      On first launch it will assist you in installing the Android SDK components.
      (or visit https://flutter.dev/docs/get-started/install/windows#android-setup for detailed instructions).
      If the Android SDK has been installed to a custom location, please use
      `flutter config --android-sdk` to update to that location.

[√] Chrome - develop for the web
[!] Android Studio (not installed)
[√] Connected device (2 available)
[!] HTTP Host Availability
    X HTTP host https://maven.google.com/ is not reachable. Reason: An error occurred while checking the HTTP host: 信号灯超时时间已到


! Doctor found issues in 3 categories.

@github-actions github-actions bot removed the waiting for customer response The Flutter team cannot make further progress on this issue until the original reporter responds label Feb 21, 2022
@maheshmnj
Copy link
Member

@guchengxi1994 I am sorry, I still couldn;t reproduce it. I did add your markdown text to the string but yet could not reproduce it.
Could you please share the updated reproducible code sample?

code sample
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:flutter_markdown/flutter_markdown.dart';

void main() => runApp(MyApp());

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return const MaterialApp(
      title: 'markdown sample',
      home: HomePage(),
    );
  }
}

class HomePage extends StatefulWidget {
  const HomePage({Key? key}) : super(key: key);

  @override
  _HomePageState createState() => _HomePageState();
}

class _HomePageState extends State<HomePage> {
  final controller = ScrollController();
  @override
  Widget build(BuildContext context) {
    return Material(
        child: BaseMarkdownPreviewPage(
      from: DataFrom.string,
      mdData: _notes,
    ));
  }
}

const String _notes = """
# Basic Markdown Demo
---
The Basic Markdown Demo shows the effect of the four Markdown extension sets
on formatting basic and extended Markdown tags.

## Overview
The Dart [markdown](https://pub.dev/packages/markdown) package parses Markdown
into HTML. The flutter_markdown package builds on this package using the
abstract syntax tree generated by the parser to make a tree of widgets instead
of HTML elements.
The markdown package supports the basic block and inline Markdown syntax
specified in the original Markdown implementation as well as a few Markdown
extensions. The markdown package uses extension sets to make extension
management easy. There are four pre-defined extension sets; none, Common Mark,
GitHub Flavored, and GitHub Web. The default extension set used by the
flutter_markdown package is GitHub Flavored.
The Basic Markdown Demo shows the effect each of the pre-defined extension sets
has on a test Markdown document with basic and extended Markdown tags. Use the
Extension Set dropdown menu to select an extension set and view the Markdown
widget's output.

***
# Title 1
## Title 2
### Title 3
#### Title 4
##### Title 5
###### Title 6
***

## Comments
Since GitHub Flavored is the default extension set, it is the initial setting
Since GitHub Flavored is the default extension set, it is the initial setting
Since GitHub Flavored is the default extension set, it is the initial setting
Since GitHub Flavored is the default extension set, it is the initial setting
Since GitHub Flavored is the default extension set, it is the initial setting
Since GitHub Flavored is the default extension set, it is the initial setting
Since GitHub Flavored is the default extension set, it is the initial setting
Since GitHub Flavored is the default extension set, it is the initial setting
Since GitHub Flavored is the default extension set, it is the initial setting
Since GitHub Flavored is the default extension set, it is the initial setting
Since GitHub Flavored is the default extension set, it is the initial setting
Since GitHub Flavored is the default extension set, it is the initial setting
Since GitHub Flavored is the default extension set, it is the initial setting
Since GitHub Flavored is the default extension set, it is the initial setting
Since GitHub Flavored is the default extension set, it is the initial setting
Since GitHub Flavored is the default extension set, it is the initial setting
Since GitHub Flavored is the default extension set, it is the initial setting
Since GitHub Flavored is the default extension set, it is the initial setting
Since GitHub Flavored is the default extension set, it is the initial setting
Since GitHub Flavored is the default extension set, it is the initial setting
Since GitHub Flavored is the default extension set, it is the initial setting
Since GitHub Flavored is the default extension set, it is the initial setting
Since GitHub Flavored is the default extension set, it is the initial setting
Since GitHub Flavored is the default extension set, it is the initial setting
Since GitHub Flavored is the default extension set, it is the initial setting
Since GitHub Flavored is the default extension set, it is the initial setting
Since GitHub Flavored is the default extension set, it is the initial setting
Since GitHub Flavored is the default extension set, it is the initial setting
Since GitHub Flavored is the default extension set, it is the initial setting
Since GitHub Flavored is the default extension set, it is the initial setting
for the formatted Markdown view in the demo.


""";

enum DataFrom { net, asset, string, file }

// ignore: must_be_immutable
class BaseMarkdownPreviewPage extends StatefulWidget {
  BaseMarkdownPreviewPage({Key? key, this.mdData, required this.from})
      : super(key: key);
  final DataFrom from;
  String? mdData;

  @override
  State<BaseMarkdownPreviewPage> createState() =>
      _BaseMarkdownPreviewPageState();
}

class _BaseMarkdownPreviewPageState extends State<BaseMarkdownPreviewPage> {
  late String markdownData;
  // ignore: prefer_typing_uninitialized_variables
  var _loadDataFuture;

  ScrollController scrollController = ScrollController();
  GlobalKey<State<Markdown>> _globalKey = GlobalKey();

  @override
  void initState() {
    super.initState();
    if (widget.from == DataFrom.string) {
      _loadDataFuture = loadDataFromString();
    } else if (widget.from == DataFrom.asset) {
      _loadDataFuture = loadDataFromAsset();
    } else if (widget.from == DataFrom.net) {
      _loadDataFuture = justAMoment();
    } else {}

    scrollController.addListener(() {
      print("maxScrollExtent:" +
          scrollController.position.maxScrollExtent.toString());
      print("offset:" + scrollController.offset.toString());
    });

    WidgetsBinding.instance!.addPostFrameCallback((timeStamp) {
      print(context.size?.height);
    });
  }

  justAMoment() async {
    await Future.delayed(const Duration(milliseconds: 1));
  }

  loadDataFromAsset() async {
    var _data = await rootBundle.loadString(widget.mdData!);
    setState(() {
      markdownData = _data;
    });
  }

  loadDataFromString() async {
    await Future.delayed(const Duration(milliseconds: 1)).then((value) {
      if (widget.mdData != null) {
        setState(() {
          markdownData = widget.mdData!;
        });
      } else {
        setState(() {
          markdownData = _notes;
        });
      }
    });
  }

  @override
  void dispose() {
    scrollController.dispose();
    super.dispose();
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: null,
      // ignore: avoid_unnecessary_containers
      body: FutureBuilder(
        future: _loadDataFuture,
        builder: (context, snap) {
          if (snap.connectionState == ConnectionState.done) {
            if (widget.from != DataFrom.net) {
              return Markdown(
                key: _globalKey,
                controller: scrollController,
                data: markdownData,
                onTapLink: (text, href, title) async {},
              );
            } else {
              return TextButton(
                  onPressed: () async {}, child: const Text('click to launch'));
            }
          } else {
            return const Center(child: Text('label.loadingSt'));
          }
        },
      ),
    );
  }
}

Thanks

@maheshmnj maheshmnj added the waiting for customer response The Flutter team cannot make further progress on this issue until the original reporter responds label Feb 21, 2022
@guchengxi1994
Copy link
Author

guchengxi1994 commented Feb 21, 2022

This is quite strange. Here are my codes.

code sample
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:flutter_markdown/flutter_markdown.dart';

class MyAppTest2 extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return const MaterialApp(
      title: 'markdown sample',
      home: HomePage(),
    );
  }
}

class HomePage extends StatefulWidget {
  const HomePage({Key? key}) : super(key: key);

  @override
  _HomePageState createState() => _HomePageState();
}

class _HomePageState extends State<HomePage> {
  final controller = ScrollController();
  @override
  Widget build(BuildContext context) {
    return Material(
        child: BaseMarkdownPreviewPage(
      from: DataFrom.string,
      mdData: _notes,
    ));
  }
}

const String _notes = """
# Basic Markdown Demo
---
The Basic Markdown Demo shows the effect of the four Markdown extension sets
on formatting basic and extended Markdown tags.

## Overview
The Dart [markdown](https://pub.dev/packages/markdown) package parses Markdown
into HTML. The flutter_markdown package builds on this package using the
abstract syntax tree generated by the parser to make a tree of widgets instead
of HTML elements.
The markdown package supports the basic block and inline Markdown syntax
specified in the original Markdown implementation as well as a few Markdown
extensions. The markdown package uses extension sets to make extension
management easy. There are four pre-defined extension sets; none, Common Mark,
GitHub Flavored, and GitHub Web. The default extension set used by the
flutter_markdown package is GitHub Flavored.
The Basic Markdown Demo shows the effect each of the pre-defined extension sets
has on a test Markdown document with basic and extended Markdown tags. Use the
Extension Set dropdown menu to select an extension set and view the Markdown
widget's output.
## Comments
Since GitHub Flavored is the default extension set, it is the initial setting
Since GitHub Flavored is the default extension set, it is the initial setting
Since GitHub Flavored is the default extension set, it is the initial setting
Since GitHub Flavored is the default extension set, it is the initial setting
Since GitHub Flavored is the default extension set, it is the initial setting
Since GitHub Flavored is the default extension set, it is the initial setting
Since GitHub Flavored is the default extension set, it is the initial setting
Since GitHub Flavored is the default extension set, it is the initial setting
Since GitHub Flavored is the default extension set, it is the initial setting
Since GitHub Flavored is the default extension set, it is the initial setting
Since GitHub Flavored is the default extension set, it is the initial setting
Since GitHub Flavored is the default extension set, it is the initial setting
Since GitHub Flavored is the default extension set, it is the initial setting
Since GitHub Flavored is the default extension set, it is the initial setting
Since GitHub Flavored is the default extension set, it is the initial setting
Since GitHub Flavored is the default extension set, it is the initial setting
Since GitHub Flavored is the default extension set, it is the initial setting
Since GitHub Flavored is the default extension set, it is the initial setting
Since GitHub Flavored is the default extension set, it is the initial setting
Since GitHub Flavored is the default extension set, it is the initial setting
Since GitHub Flavored is the default extension set, it is the initial setting
Since GitHub Flavored is the default extension set, it is the initial setting
Since GitHub Flavored is the default extension set, it is the initial setting
Since GitHub Flavored is the default extension set, it is the initial setting
Since GitHub Flavored is the default extension set, it is the initial setting
Since GitHub Flavored is the default extension set, it is the initial setting
Since GitHub Flavored is the default extension set, it is the initial setting
Since GitHub Flavored is the default extension set, it is the initial setting
Since GitHub Flavored is the default extension set, it is the initial setting
Since GitHub Flavored is the default extension set, it is the initial setting
for the formatted Markdown view in the demo.
Since GitHub Flavored is the default extension set, it is the initial setting
Since GitHub Flavored is the default extension set, it is the initial setting
Since GitHub Flavored is the default extension set, it is the initial setting
Since GitHub Flavored is the default extension set, it is the initial setting
Since GitHub Flavored is the default extension set, it is the initial setting
Since GitHub Flavored is the default extension set, it is the initial setting
Since GitHub Flavored is the default extension set, it is the initial setting
Since GitHub Flavored is the default extension set, it is the initial setting
Since GitHub Flavored is the default extension set, it is the initial setting
Since GitHub Flavored is the default extension set, it is the initial setting
Since GitHub Flavored is the default extension set, it is the initial setting
Since GitHub Flavored is the default extension set, it is the initial setting
Since GitHub Flavored is the default extension set, it is the initial setting
Since GitHub Flavored is the default extension set, it is the initial setting
Since GitHub Flavored is the default extension set, it is the initial setting
Since GitHub Flavored is the default extension set, it is the initial setting
Since GitHub Flavored is the default extension set, it is the initial setting
Since GitHub Flavored is the default extension set, it is the initial setting
Since GitHub Flavored is the default extension set, it is the initial setting
Since GitHub Flavored is the default extension set, it is the initial setting
Since GitHub Flavored is the default extension set, it is the initial setting
Since GitHub Flavored is the default extension set, it is the initial setting
Since GitHub Flavored is the default extension set, it is the initial setting
Since GitHub Flavored is the default extension set, it is the initial setting
Since GitHub Flavored is the default extension set, it is the initial setting
Since GitHub Flavored is the default extension set, it is the initial setting
Since GitHub Flavored is the default extension set, it is the initial setting
Since GitHub Flavored is the default extension set, it is the initial setting
Since GitHub Flavored is the default extension set, it is the initial setting
Since GitHub Flavored is the default extension set, it is the initial setting
for the formatted Markdown view in the demo.

***
# Title 1
## Title 2
### Title 3
#### Title 4
##### Title 5
###### Title 6
***

""";

enum DataFrom { net, asset, string, file }

// ignore: must_be_immutable
class BaseMarkdownPreviewPage extends StatefulWidget {
  BaseMarkdownPreviewPage({Key? key, this.mdData, required this.from})
      : super(key: key);
  final DataFrom from;
  String? mdData;

  @override
  State<BaseMarkdownPreviewPage> createState() =>
      _BaseMarkdownPreviewPageState();
}

class _BaseMarkdownPreviewPageState extends State<BaseMarkdownPreviewPage> {
  late String markdownData;
  // ignore: prefer_typing_uninitialized_variables
  var _loadDataFuture;

  ScrollController scrollController = ScrollController();
  GlobalKey<State<Markdown>> _globalKey = GlobalKey();

  @override
  void initState() {
    super.initState();
    if (widget.from == DataFrom.string) {
      _loadDataFuture = loadDataFromString();
    } else if (widget.from == DataFrom.asset) {
      _loadDataFuture = loadDataFromAsset();
    } else if (widget.from == DataFrom.net) {
      _loadDataFuture = justAMoment();
    } else {}

    scrollController.addListener(() {
      print("maxScrollExtent:" +
          scrollController.position.maxScrollExtent.toString());
      print("offset:" + scrollController.offset.toString());
    });

    WidgetsBinding.instance!.addPostFrameCallback((timeStamp) {
      print(context.size?.height);
    });
  }

  justAMoment() async {
    await Future.delayed(const Duration(milliseconds: 1));
  }

  loadDataFromAsset() async {
    var _data = await rootBundle.loadString(widget.mdData!);
    setState(() {
      markdownData = _data;
    });
  }

  loadDataFromString() async {
    await Future.delayed(const Duration(milliseconds: 1)).then((value) {
      if (widget.mdData != null) {
        setState(() {
          markdownData = widget.mdData!;
        });
      } else {
        setState(() {
          markdownData = _notes;
        });
      }
    });
  }

  @override
  void dispose() {
    scrollController.dispose();
    super.dispose();
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: null,
      // ignore: avoid_unnecessary_containers
      body: FutureBuilder(
        future: _loadDataFuture,
        builder: (context, snap) {
          if (snap.connectionState == ConnectionState.done) {
            if (widget.from != DataFrom.net) {
              return Markdown(
                key: _globalKey,
                controller: scrollController,
                data: markdownData,
                onTapLink: (text, href, title) async {},
              );
            } else {
              return TextButton(
                  onPressed: () async {}, child: const Text('click to launch'));
            }
          } else {
            return const Center(child: Text('label.loadingSt'));
          }
        },
      ),
    );
  }
}

Besides, I tested it on web, not an android simulator.Using flutter run -d chrome --web-renderer html

code_find_008

@github-actions github-actions bot removed the waiting for customer response The Flutter team cannot make further progress on this issue until the original reporter responds label Feb 21, 2022
@carmel
Copy link

carmel commented Feb 21, 2022

I'm having problems with maxScrollExtent not being fixed on both iOs and Android.

I also tried to scroll directly to the index of the SliverList, and that also failed. my repo

My idea is to save each widget height in the SliverList to a list by getting it, and then accumulate it from the first widget until the result is greater than the current view's offset, then consider the last index as the index value that can be observed on the current view. If the current view does not change state after initialization, then the exact index can still be fetched, and once thesetState occurs, the value in the list that holds the widget height will be wrong.

@maheshmnj
Copy link
Member

Thanks for the code sample @guchengxi1994, I was able to reproduce the issue on stable and the master channel. I can confirm adding the below markdown to string reproduces the issue.

***
# Title 1
## Title 2
### Title 3
#### Title 4
##### Title 5
###### Title 6
***
code sample
import 'package:flutter/material.dart';
import 'package:flutter_markdown/flutter_markdown.dart';

void main() {
  runApp(MyAppTest2());
}

class MyAppTest2 extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return const MaterialApp(
      title: 'markdown sample',
      home: HomePage(),
    );
  }
}

class HomePage extends StatefulWidget {
  const HomePage({Key? key}) : super(key: key);

  @override
  _HomePageState createState() => _HomePageState();
}

class _HomePageState extends State<HomePage> {
  final controller = ScrollController();
  @override
  Widget build(BuildContext context) {
    return const Material(child: BaseMarkdownPreviewPage());
  }
}

const String _notes = """
# Basic Markdown Demo
---
The Basic Markdown Demo shows the effect of the four Markdown extension sets
on formatting basic and extended Markdown tags.

## Overview
The Dart [markdown](https://pub.dev/packages/markdown) package parses Markdown
into HTML. The flutter_markdown package builds on this package using the
abstract syntax tree generated by the parser to make a tree of widgets instead
of HTML elements.
The markdown package supports the basic block and inline Markdown syntax
specified in the original Markdown implementation as well as a few Markdown
extensions. The markdown package uses extension sets to make extension
management easy. There are four pre-defined extension sets; none, Common Mark,
GitHub Flavored, and GitHub Web. The default extension set used by the
flutter_markdown package is GitHub Flavored.
The Basic Markdown Demo shows the effect each of the pre-defined extension sets
has on a test Markdown document with basic and extended Markdown tags. Use the
Extension Set dropdown menu to select an extension set and view the Markdown
widget's output.
## Comments
Since GitHub Flavored is the default extension set, it is the initial setting
Since GitHub Flavored is the default extension set, it is the initial setting
Since GitHub Flavored is the default extension set, it is the initial setting
Since GitHub Flavored is the default extension set, it is the initial setting
Since GitHub Flavored is the default extension set, it is the initial setting
Since GitHub Flavored is the default extension set, it is the initial setting
Since GitHub Flavored is the default extension set, it is the initial setting
Since GitHub Flavored is the default extension set, it is the initial setting
Since GitHub Flavored is the default extension set, it is the initial setting
Since GitHub Flavored is the default extension set, it is the initial setting
Since GitHub Flavored is the default extension set, it is the initial setting
Since GitHub Flavored is the default extension set, it is the initial setting
Since GitHub Flavored is the default extension set, it is the initial setting
Since GitHub Flavored is the default extension set, it is the initial setting
Since GitHub Flavored is the default extension set, it is the initial setting
Since GitHub Flavored is the default extension set, it is the initial setting
Since GitHub Flavored is the default extension set, it is the initial setting
Since GitHub Flavored is the default extension set, it is the initial setting
Since GitHub Flavored is the default extension set, it is the initial setting
Since GitHub Flavored is the default extension set, it is the initial setting
Since GitHub Flavored is the default extension set, it is the initial setting
Since GitHub Flavored is the default extension set, it is the initial setting
Since GitHub Flavored is the default extension set, it is the initial setting
Since GitHub Flavored is the default extension set, it is the initial setting
Since GitHub Flavored is the default extension set, it is the initial setting
Since GitHub Flavored is the default extension set, it is the initial setting
Since GitHub Flavored is the default extension set, it is the initial setting
Since GitHub Flavored is the default extension set, it is the initial setting
Since GitHub Flavored is the default extension set, it is the initial setting
Since GitHub Flavored is the default extension set, it is the initial setting
for the formatted Markdown view in the demo.
Since GitHub Flavored is the default extension set, it is the initial setting
Since GitHub Flavored is the default extension set, it is the initial setting
Since GitHub Flavored is the default extension set, it is the initial setting
Since GitHub Flavored is the default extension set, it is the initial setting
Since GitHub Flavored is the default extension set, it is the initial setting
Since GitHub Flavored is the default extension set, it is the initial setting
Since GitHub Flavored is the default extension set, it is the initial setting
Since GitHub Flavored is the default extension set, it is the initial setting
Since GitHub Flavored is the default extension set, it is the initial setting
Since GitHub Flavored is the default extension set, it is the initial setting
Since GitHub Flavored is the default extension set, it is the initial setting
Since GitHub Flavored is the default extension set, it is the initial setting
Since GitHub Flavored is the default extension set, it is the initial setting
Since GitHub Flavored is the default extension set, it is the initial setting
Since GitHub Flavored is the default extension set, it is the initial setting
Since GitHub Flavored is the default extension set, it is the initial setting
Since GitHub Flavored is the default extension set, it is the initial setting
Since GitHub Flavored is the default extension set, it is the initial setting
Since GitHub Flavored is the default extension set, it is the initial setting
Since GitHub Flavored is the default extension set, it is the initial setting
Since GitHub Flavored is the default extension set, it is the initial setting
Since GitHub Flavored is the default extension set, it is the initial setting
Since GitHub Flavored is the default extension set, it is the initial setting
Since GitHub Flavored is the default extension set, it is the initial setting
Since GitHub Flavored is the default extension set, it is the initial setting
Since GitHub Flavored is the default extension set, it is the initial setting
Since GitHub Flavored is the default extension set, it is the initial setting
Since GitHub Flavored is the default extension set, it is the initial setting
Since GitHub Flavored is the default extension set, it is the initial setting
Since GitHub Flavored is the default extension set, it is the initial setting
for the formatted Markdown view in the demo.

Removing the below lines fixes the markdown maxScrollExtent issue

***
# Title 1
## Title 2
### Title 3
#### Title 4
##### Title 5
###### Title 6
***

""";

enum DataFrom { net, asset, string, file }

// ignore: must_be_immutable
class BaseMarkdownPreviewPage extends StatefulWidget {
  const BaseMarkdownPreviewPage({Key? key}) : super(key: key);

  @override
  State<BaseMarkdownPreviewPage> createState() =>
      _BaseMarkdownPreviewPageState();
}

class _BaseMarkdownPreviewPageState extends State<BaseMarkdownPreviewPage> {
  late String markdownData;

  ScrollController scrollController = ScrollController();

  @override
  void initState() {
    super.initState();
    scrollController.addListener(() {
      print("maxScrollExtent:" +
          scrollController.position.maxScrollExtent.toString());
      print("offset:" + scrollController.offset.toString());
    });
  }

  @override
  void dispose() {
    scrollController.dispose();
    super.dispose();
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
        // ignore: avoid_unnecessary_containers
        body: Markdown(
      controller: scrollController,
      data: _notes,
      onTapLink: (text, href, title) async {},
    ));
  }
}
logs
mahesh@Maheshs-MacBook-Air-M1 maps_sample % flutter run -d chrome
Running "flutter pub get" in maps_sample...                      1,183ms
Launching lib/main.dart on Chrome in debug mode...
Waiting for connection from debug service on Chrome...             17.4s
DartUri: Unresolved uri: dart:web_sql
DartUri: Unresolved uri: dart:ui
This app is linked to the debug service: ws://127.0.0.1:52881/2ejIP4Tj-rk=/ws
Debug service listening on ws://127.0.0.1:52881/2ejIP4Tj-rk=/ws

💪 Running with sound null safety 💪

🔥  To hot restart changes while running, press "r" or "R".
For a more detailed help message, press "h". To quit, press "q".

An Observatory debugger and profiler on Chrome is available at: http://127.0.0.1:52881/2ejIP4Tj-rk=
The Flutter DevTools debugger and profiler on Chrome is available at:
http://127.0.0.1:9101?uri=http://127.0.0.1:52881/2ejIP4Tj-rk=
maxScrollExtent:911.578947368421
offset:5
maxScrollExtent:911.578947368421
offset:51
maxScrollExtent:744.0454545454545
offset:82
maxScrollExtent:621.6800000000001
offset:111
maxScrollExtent:549.8518518518517
offset:151
maxScrollExtent:455.9333333333334
offset:194
maxScrollExtent:423
offset:239
maxScrollExtent:423
offset:284
maxScrollExtent:423
offset:327
maxScrollExtent:423
offset:369
maxScrollExtent:423
offset:414
maxScrollExtent:423
offset:423
maxScrollExtent:423
offset:422
maxScrollExtent:423
offset:419
maxScrollExtent:423
offset:413
maxScrollExtent:423
offset:404
maxScrollExtent:423
offset:392
maxScrollExtent:423
offset:375
maxScrollExtent:423
offset:357
maxScrollExtent:423
offset:340
maxScrollExtent:423
offset:321
maxScrollExtent:423
offset:304
maxScrollExtent:423
offset:284
maxScrollExtent:423
offset:258
maxScrollExtent:423
offset:230
maxScrollExtent:423
offset:202
maxScrollExtent:423
offset:174
maxScrollExtent:423
offset:147
maxScrollExtent:455.9333333333334
offset:121
maxScrollExtent:513.3571428571429
offset:92
maxScrollExtent:621.6800000000001
offset:65
maxScrollExtent:706
offset:41
maxScrollExtent:801.952380952381
offset:19
maxScrollExtent:842.4000000000001
offset:0
maxScrollExtent:911.578947368421
offset:1
maxScrollExtent:911.578947368421
offset:7
maxScrollExtent:911.578947368421
offset:21
maxScrollExtent:842.4000000000001
offset:38
maxScrollExtent:801.952380952381
offset:54
maxScrollExtent:706
offset:72
maxScrollExtent:706
offset:87
maxScrollExtent:621.6800000000001
offset:99
maxScrollExtent:579.6153846153845
offset:102
maxScrollExtent:579.6153846153845
offset:117
maxScrollExtent:549.8518518518517
offset:136
maxScrollExtent:487.9310344827586
offset:156
maxScrollExtent:423
offset:177
maxScrollExtent:423
offset:198
maxScrollExtent:423
offset:218
maxScrollExtent:423
offset:237
maxScrollExtent:423
offset:259
maxScrollExtent:423
offset:279
maxScrollExtent:423
offset:298
maxScrollExtent:423
offset:315
maxScrollExtent:423
offset:331
maxScrollExtent:423
offset:345
maxScrollExtent:423
offset:358
maxScrollExtent:423
offset:370
maxScrollExtent:423
offset:381
maxScrollExtent:423
offset:391
maxScrollExtent:423
offset:400
maxScrollExtent:423
offset:408
maxScrollExtent:423
offset:416
maxScrollExtent:423
offset:423
maxScrollExtent:423
offset:420
maxScrollExtent:423
offset:418
maxScrollExtent:423
offset:411
maxScrollExtent:423
offset:403
maxScrollExtent:423
offset:397
maxScrollExtent:423
offset:392
maxScrollExtent:423
offset:387
maxScrollExtent:423
offset:382
maxScrollExtent:423
offset:375
maxScrollExtent:423
offset:367
maxScrollExtent:423
offset:361
maxScrollExtent:423
offset:355
maxScrollExtent:423
offset:350
maxScrollExtent:423
offset:347
maxScrollExtent:423
offset:344
maxScrollExtent:423
offset:341
maxScrollExtent:423
offset:338
maxScrollExtent:423
offset:335
maxScrollExtent:423
offset:332
maxScrollExtent:423
offset:328
maxScrollExtent:423
offset:323
maxScrollExtent:423
offset:316
maxScrollExtent:423
offset:306
maxScrollExtent:423
offset:295
maxScrollExtent:423
offset:283
maxScrollExtent:423
offset:273
maxScrollExtent:423
offset:263
maxScrollExtent:423
offset:251
maxScrollExtent:423
offset:238
maxScrollExtent:423
offset:225
maxScrollExtent:423
offset:212
maxScrollExtent:423
offset:200
maxScrollExtent:423
offset:188
maxScrollExtent:423
offset:175
maxScrollExtent:423
offset:162
maxScrollExtent:423
offset:151
maxScrollExtent:455.9333333333334
offset:141
maxScrollExtent:487.9310344827586
offset:132
maxScrollExtent:487.9310344827586
offset:123
maxScrollExtent:513.3571428571429
offset:115
maxScrollExtent:549.8518518518517
offset:108
maxScrollExtent:549.8518518518517
offset:101
maxScrollExtent:579.6153846153845
offset:95
maxScrollExtent:621.6800000000001
offset:89
maxScrollExtent:621.6800000000001
offset:84
maxScrollExtent:621.6800000000001
offset:79
maxScrollExtent:656.9166666666665
offset:74
maxScrollExtent:656.9166666666665
offset:70
maxScrollExtent:706
offset:66
maxScrollExtent:706
offset:65
maxScrollExtent:706
offset:60
maxScrollExtent:706
offset:54
maxScrollExtent:706
offset:48
maxScrollExtent:744.0454545454545
offset:41
maxScrollExtent:801.952380952381
offset:28
maxScrollExtent:801.952380952381
offset:14
maxScrollExtent:911.578947368421
offset:0
flutter doctor -v
[✓] Flutter (Channel stable, 2.10.2, on macOS 12.1 21C52 darwin-arm, locale en-GB)
    • Flutter version 2.10.2 at /Users/mahesh/Documents/flutter
    • Upstream repository https://github.com/flutter/flutter.git
    • Framework revision 097d3313d8 (2 days ago), 2022-02-18 19:33:08 -0600
    • Engine revision a83ed0e5e3
    • Dart version 2.16.1
    • DevTools version 2.9.2

[✓] Android toolchain - develop for Android devices (Android SDK version 31.0.0)
    • Android SDK at /Users/mahesh/Library/Android/sdk
    • Platform android-31, build-tools 31.0.0
    • ANDROID_HOME = /Users/mahesh/Library/Android/sdk
    • Java binary at: /Applications/Android Studio.app/Contents/jre/jdk/Contents/Home/bin/java
    • Java version OpenJDK Runtime Environment (build 11.0.8+10-b944.6916264)
    • All Android licenses accepted.

[✓] Xcode - develop for iOS and macOS (Xcode 13.2.1)
    • Xcode at /Applications/Xcode.app/Contents/Developer
    • CocoaPods version 1.10.2

[✓] Chrome - develop for the web
    • Chrome at /Applications/Google Chrome.app/Contents/MacOS/Google Chrome

[✓] Android Studio (version 4.2)
    • Android Studio at /Applications/Android Studio.app/Contents
    • Flutter plugin can be installed from:
      🔨 https://plugins.jetbrains.com/plugin/9212-flutter
    • Dart plugin can be installed from:
      🔨 https://plugins.jetbrains.com/plugin/6351-dart
    • Java version OpenJDK Runtime Environment (build 11.0.8+10-b944.6916264)

[✓] IntelliJ IDEA Community Edition (version 2021.2.1)
    • IntelliJ at /Applications/IntelliJ IDEA CE.app
    • Flutter plugin version 61.2.4
    • Dart plugin version 212.5080.8

[✓] VS Code (version 1.63.2)
    • VS Code at /Applications/Visual Studio Code.app/Contents
    • Flutter extension version 3.34.0

[✓] Connected device (3 available)
    • Redmi K20 Pro (mobile) • 192.168.1.2:5555 • android-arm64  • Android 11 (API 30)
    • macOS (desktop)        • macos            • darwin-arm64   • macOS 12.1 21C52 darwin-arm
    • Chrome (web)           • chrome           • web-javascript • Google Chrome 98.0.4758.102

[✓] HTTP Host Availability
    • All required HTTP hosts are available

• No issues found!
[✓] Flutter (Channel master, 2.11.0-0.0.pre.582, on macOS 12.1 21C52 darwin-arm, locale en-GB)
    • Flutter version 2.11.0-0.0.pre.582 at /Users/mahesh/Documents/flutter_master
    • Upstream repository https://github.com/flutter/flutter.git
    • Framework revision 9514106108 (5 days ago), 2022-02-16 00:00:11 -0500
    • Engine revision b09cf53269
    • Dart version 2.17.0 (build 2.17.0-105.0.dev)
    • DevTools version 2.10.0

[✓] Android toolchain - develop for Android devices (Android SDK version 31.0.0)
    • Android SDK at /Users/mahesh/Library/Android/sdk
    • Platform android-31, build-tools 31.0.0
    • ANDROID_HOME = /Users/mahesh/Library/Android/sdk
    • Java binary at: /Applications/Android Studio.app/Contents/jre/jdk/Contents/Home/bin/java
    • Java version OpenJDK Runtime Environment (build 11.0.8+10-b944.6916264)
    • All Android licenses accepted.

[✓] Xcode - develop for iOS and macOS (Xcode 13.2.1)
    • Xcode at /Applications/Xcode.app/Contents/Developer
    • CocoaPods version 1.10.2

[✓] Chrome - develop for the web
    • Chrome at /Applications/Google Chrome.app/Contents/MacOS/Google Chrome

[✓] Android Studio (version 4.2)
    • Android Studio at /Applications/Android Studio.app/Contents
    • Flutter plugin can be installed from:
      🔨 https://plugins.jetbrains.com/plugin/9212-flutter
    • Dart plugin can be installed from:
      🔨 https://plugins.jetbrains.com/plugin/6351-dart
    • Java version OpenJDK Runtime Environment (build 11.0.8+10-b944.6916264)

[✓] IntelliJ IDEA Community Edition (version 2021.2.1)
    • IntelliJ at /Applications/IntelliJ IDEA CE.app
    • Flutter plugin version 61.2.4
    • Dart plugin version 212.5080.8

[✓] VS Code (version 1.63.2)
    • VS Code at /Applications/Visual Studio Code.app/Contents
    • Flutter extension version 3.34.0

[✓] Connected device (3 available)
    • Redmi K20 Pro (mobile) • 192.168.1.2:5555 • android-arm64  • Android 11 (API 30)
    • macOS (desktop)        • macos            • darwin-arm64   • macOS 12.1 21C52 darwin-arm
    • Chrome (web)           • chrome           • web-javascript • Google Chrome 98.0.4758.102

[✓] HTTP Host Availability
    • All required HTTP hosts are available

• No issues found!

@maheshmnj maheshmnj added found in release: 2.10 Found to occur in 2.10 found in release: 2.11 Found to occur in 2.11 has reproducible steps The issue has been confirmed reproducible and is ready to work on p: first party p: flutter_markdown flutter/packages flutter_markdown package flutter/packages repository. See also p: labels. and removed in triage Presently being triaged by the triage team labels Feb 22, 2022
@stuartmorgan stuartmorgan added the P2 Important issues not at the top of the work list label Feb 22, 2022
@wangzv
Copy link

wangzv commented May 18, 2022

set the scrollview cacheExtent to a large value (eg : double.maxFinite) can fix this issue,but maybe affecting performance.

@JackyMR
Copy link

JackyMR commented Jan 11, 2023

I get similar problems, too. The init maxScrollExtent not equals the scrollcontroller's listener maxScrollExtent. But when setting the ListView cacheExtent to double.maxFinite, it works well.

@SitholeWB
Copy link

I was facing the same issue, I ended up looking for another better library. This one worked for me https://pub.dev/packages/markdown_widget

@flutter-triage-bot flutter-triage-bot bot added team-ecosystem Owned by Ecosystem team triaged-ecosystem Triaged by Ecosystem team labels Jul 8, 2023
@stuartmorgan stuartmorgan added P3 Issues that are less important to the Flutter project and removed P2 Important issues not at the top of the work list labels Feb 15, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
found in release: 2.10 Found to occur in 2.10 found in release: 2.11 Found to occur in 2.11 has reproducible steps The issue has been confirmed reproducible and is ready to work on p: flutter_markdown flutter/packages flutter_markdown P3 Issues that are less important to the Flutter project package flutter/packages repository. See also p: labels. team-ecosystem Owned by Ecosystem team triaged-ecosystem Triaged by Ecosystem team
Projects
None yet
Development

No branches or pull requests

7 participants