Flutter, ListView.builder doesn't renders fully on screen when in Positioned widget and can't use Expanded or Flexible? widgets

Viewed 110

Need to have ListView.builder build ListTiles under certain part of Text inside RichText widget

Doing it with Stack widget, Im getting position of element in RichText by finding its Offset position, for this need to use Key, though TextSpan doesn't have Key property, so im using InkWell widget inside RichText instead (I presume I can turn off animations associated with it).

It works really well, ListTiles are following InkWell accordingly (need to add few lines of code to make it seamless).

Though still have big issue, can't get ListView.builder to display items that are outside of Text widget, can't wrap it in Extended() or Flexible() widget, getting error, incorrect use of parent widget, I presume that's because I use Stack widget and don't know what else to do. Please let me know if someone can solve this issue.

There are buttons on the page, so one can add or remove text, as to see it in action. And I've added Text before and after ListTile anchor element so it can be better seen as it is being displayed only inside Text widget

import 'package:flutter/material.dart';

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

/// This is the main application widget.
class MyApp extends StatelessWidget {
  const MyApp({Key? key}) : super(key: key);

  static const String _title = 'Flutter Code Sample';

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Flutter Demo',
      theme: ThemeData(
        // This is the theme of your application.
        // notice "hot reload" button
        primarySwatch: Colors.blue,
      ),
      home: GetPosition(),
    );
  }
}

class GetPosition extends StatefulWidget {
  String changeText =
      'dynamicaly changing text dynamicaly changing text dynamicaly changing text dynamicaly changing text dynamicaly changing text dynamicaly changing text';
  @override
  _GetPositionState createState() => _GetPositionState();
}

class _GetPositionState extends State<GetPosition> {
  GlobalKey _key = GlobalKey();
  double _x = 0, _y = 0;

  // this function is trigger when the user presses the floating button
  void _getOffset(GlobalKey key) {
    RenderBox? box = key.currentContext!.findRenderObject() as RenderBox?;
    Offset position = box!.localToGlobal(Offset.zero);
    setState(() {
      _x = position.dx;
      _y = position.dy;
    });
  }

  @override
  Widget build(BuildContext context) {
    final List<String> entries = <String>[
      _x != null ? "X: ${_x.toInt()}" : '',
      _y != null ? "Y: $_y" : '',
      _x != null ? 'Entry A' : '',
      _x != null ? 'Entry B' : '',
      _x != null ? 'EntryC' : ''
    ];
    return Scaffold(
      body: Stack(children: [
        RichText(
          textAlign: TextAlign.left,
          text: TextSpan(
            text: '${widget.changeText}',
            style: TextStyle(color: Colors.black, fontSize: 18.0),
            children: [
              WidgetSpan(
                child: InkWell(
                  splashFactory: NoSplash.splashFactory,
                  key: _key,
                  onTap: () {},
                  child: Text(
                    " ListView.builder",
                    style: TextStyle(color: Colors.red, fontSize: 18.0),
                  ),
                ),
              ),
              TextSpan(
                text: '${widget.changeText}',
                style: TextStyle(color: Colors.black, fontSize: 18.0),
              ),
            ],
          ),
        ),
        Positioned(
          top: _y + 10,
          left: _x,
          child: SizedBox(
            width: 310,
            height: 200,
            child: Builder(builder: (context) {
              return ListView.builder(
                  padding: EdgeInsets.all(0.0),
                  itemCount: entries.length,
                  itemBuilder: (BuildContext context, int index) {
                    return ListTile(
                      dense: true,
                      // height: 300,
                      // color: Colors.amber[colorCodes[index]],
                      title: Text(
                        '${entries[index]}',
                        style: TextStyle(color: Colors.red, fontSize: 18.0),
                      ),
                    );
                  });
            }),
          ),
        ),
        Row(children: [
          ElevatedButton(
              onPressed: () {
                // randomPosition();

                _getOffset(_key);
                widget.changeText = widget.changeText + ' add text  dsds';
                // print(randomLeft);
                // print(randomTop);
                setState(() {});
              },
              child: Text('Add some text')),
          ElevatedButton(
            onPressed: () {
              _getOffset(_key);
              if (widget.changeText.length > 10) {
                widget.changeText = widget.changeText
                    .substring(10, widget.changeText.length - 1);
              } else {
                if (widget.changeText.length > 0) {
                  widget.changeText = widget.changeText
                      .substring(0, widget.changeText.length - 1);
                } else {}
              }

              setState(() {});
            },
            child: const Text('Delete some Text'),
          )
        ]),
      ]),
      floatingActionButton: FloatingActionButton(
          onPressed: () {
            // randomPosition();

            _getOffset(_key);
            widget.changeText = widget.changeText + ' add text  dsds';
            // print(randomLeft);
            // print(randomTop);
            setState(() {});
          },
          child: Icon(Icons.calculate)),
    );
  }
}
1 Answers

Need to add "clipBehavior: Clip.none," to Stack widget to display Positioned widget outside of Stack widget

  import 'package:flutter/material.dart';

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

/// This is the main application widget.
class MyApp extends StatelessWidget {
  const MyApp({Key? key}) : super(key: key);

  static const String _title = 'Flutter Code Sample';

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Flutter Demo',
      theme: ThemeData(
        // This is the theme of your application.
        // notice "hot reload" button
        primarySwatch: Colors.blue,
      ),
      home: Scaffold(body: GetPosition()),
    );
  }
}

class GetPosition extends StatefulWidget {
  String changeText =
      'dynamicaly changing text dynamicaly changing text dynamicaly changing text dynamicaly changing text dynamicaly changing text dynamicaly changing text';
  @override
  _GetPositionState createState() => _GetPositionState();
}

class _GetPositionState extends State<GetPosition> {
  GlobalKey _key = GlobalKey();
  double _x = 0, _y = 0;

  // this function is trigger when the user presses the floating button
  void _getOffset(GlobalKey key) {
    RenderBox? box = key.currentContext!.findRenderObject() as RenderBox?;
    Offset position = box!.localToGlobal(Offset.zero);
    setState(() {
      _x = position.dx;
      _y = position.dy;
    });
  }

  @override
  Widget build(BuildContext context) {
    final List<int> colorCodes = <int>[100, 200, 300, 500, 600];
    final List<String> entries = <String>[
      _x != null ? "X: $_x" : '',
      _y != null ? "Y: $_y" : '',
      _x != null ? 'Entry A' : '',
      _x != null ? 'Entry B' : '',
      _x != null ? 'EntryC' : ''
    ];
    return SafeArea(
      child: SingleChildScrollView(
        child: LayoutBuilder(
            builder: (BuildContext context, BoxConstraints constraints) {
          double screenWidth = MediaQuery.of(context).size.width;
          return Column(
              mainAxisSize: MainAxisSize.max,
              crossAxisAlignment: CrossAxisAlignment.stretch,
              children: [
                Stack(clipBehavior: Clip.none, children: [
                  RichText(
                    textAlign: TextAlign.left,
                    text: TextSpan(
                      text: '${widget.changeText}',
                      style: TextStyle(color: Colors.black, fontSize: 18.0),
                      children: [
                        WidgetSpan(
                          child: InkWell(
                            splashFactory: NoSplash.splashFactory,
                            key: _key,
                            onTap: () {},
                            child: Text(
                              " ListView.builder",
                              style:
                                  TextStyle(color: Colors.red, fontSize: 18.0),
                            ),
                          ),
                        ),
                      ],
                    ),
                  ),
                  Positioned(
                    top: _y + 40,
                    left: _x + 50,
                    child: Container(
                      width: 200,
                      height: 200,
                      child: Builder(builder: (context) {
                        return ListView.builder(
                            padding: EdgeInsets.all(0.0),
                            itemCount: entries.length,
                            itemBuilder: (BuildContext context, int index) {
                              return Container(
                                color: Colors.amber[colorCodes[index]],
                                child:
                                    // dense: true,
                                    // height: 300,

                                    // children: [
                                    Text(
                                  '${entries[index]}',
                                  style: TextStyle(
                                      color: Colors.red, fontSize: 18.0),
                                ),
                                // ],
                              );
                            });
                      }),
                    ),
                  ),
                  Column(
                      crossAxisAlignment: CrossAxisAlignment.center,
                      mainAxisAlignment: MainAxisAlignment.start,
                      children: [
                        ElevatedButton(
                            onPressed: () {
                              // randomPosition();
                              print(screenWidth);
                              _getOffset(_key);
                              widget.changeText = widget.changeText +
                                  ' dynamic text added dynamic text added dynamic text added dynamic text added dynamic text added dynamic text added';
                              // print(randomLeft);
                              // print(randomTop);
                              setState(() {});
                            },
                            child: Text('Add some text')),
                        ElevatedButton(
                          onPressed: () {
                            print(screenWidth);
                            _getOffset(_key);
                            if (widget.changeText.length > 25) {
                              widget.changeText = widget.changeText
                                  .substring(25, widget.changeText.length - 1);
                            } else {
                              if (widget.changeText.length > 0) {
                                widget.changeText = widget.changeText
                                    .substring(0, widget.changeText.length - 1);
                              } else {}
                            }

                            setState(() {});
                          },
                          child: const Text('Delete some Text'),
                        )
                      ]),
                ]),
              ]);
        }),
      ),
    );
  }
}
Related