5

I'm currently trying to make a custom widget in flutter. A simple "A to Z scroller" on right of a list of elements to jump on indexes. My problem is that actually i need to use the size of the list widget to determinate the size of the font for the letters.

To illustrate: enter image description here

I added the list as child of a custom class to got it's height from context. I tryed to get the size with the context.size.heigth in the "build" method but i got an error because the widget is not build. Then i tryed to exec an async method like i read here : Stack overflow post

The only location where i can got the context.size.height without error is in the onVerticalDragUpdate of my gesture detector.

There is my actual code:

class _MyHomePageState extends State<MyHomePage> {
  @override
  Widget build(BuildContext context) {  
    return Scaffold(
      appBar: AppBar(
        title: Text(widget.title),
      ),
      body: new AtoZSlider(child: _builList()),
    );
  }
}

Widget _builList() { //test list
  return ListView.builder(
    padding: EdgeInsets.all(8.0),
    itemExtent: 20.0,
    itemCount: 1000,
    itemBuilder: (BuildContext context, int index) {
      return Text('entry $index');
    },
  );
}

class AtoZSlider extends StatefulWidget {
  final Widget child;

  AtoZSlider({this.child});

  @override
  _AtoZSlider createState() => new _AtoZSlider();
}

class _AtoZSlider extends State<AtoZSlider> {
  double _offsetContainer;
  double _heightscroller;
  bool _isHeightSetup;
  var _text;
  var _alphabet;

  @override
  void initState() {
    super.initState();
    _offsetContainer = 0.0;
    _isHeightSetup = false;
    _heightscroller = 14.0; //default value that i want to calculate with context size
    _alphabet = [
      '#',
      'A',
      'B',
      'C',
      'D',
      'E',
      'F',
      'G',
      'H',
      'I',
      'J',
      'K',
      'L',
      'M',
      'N',
      'O',
      'P',
      'Q',
      'R',
      'S',
      'T',
      'U',
      'V',
      'W',
      'X',
      'Y',
      'Z'
    ];
    _text = _alphabet[0];
  }

  @override
  Widget build(BuildContext context) {
    return  Stack(alignment: Alignment.topRight, children: [
      widget.child,
      GestureDetector(
        child: Container(
            child: Text(_text, style: new TextStyle(fontSize: _heightscroller),),
            height: _heightscroller,
            margin: EdgeInsets.only(top: _offsetContainer)),
        onVerticalDragUpdate: (DragUpdateDetails details) {
          setState(() {

            if ((_offsetContainer + details.delta.dy) >= 0 &&
                (_offsetContainer + details.delta.dy) <=
                    (context.size.height - _heightscroller)) { // to move my scroller on the vertical axis and not out of band using context.size.height
              _offsetContainer += details.delta.dy; 

            }

          });
        },
      )
    ]);
  }

}

Is there some way to init my 'widget text font size' depending of the "list size height" ?

Thank you a lot for any kind of help.

OOM
  • 728
  • 7
  • 22
  • 1
    I made a simple implementation here: https://github.com/oom-/AtoZscrollflutter- if it can help – OOM Mar 09 '19 at 14:06

2 Answers2

3

A widget cannot depend on the size of another widget. It can, on the other hand, depends on constraints.

To do so, you can use LayoutBuilder to obtain the constraints and build widgets accordingly:

Widget build(BuildContext context) {
  return Scaffold(
    appBar: AppBar(title: Text("Hello World")),
    body: LayoutBuilder(
      builder: (context, constraints) {
        if (constraints.biggest.width > 100) {
          return Text('Hello');
        }
        return Container();
      },
    ),
  );
}
Rémi Rousselet
  • 256,336
  • 79
  • 519
  • 432
  • 1
    Yes but if i want that the list fill a container by exemple i will have to make a stack with defined size for my list and scroll for every phone size ? In the builder the *context.size.height* is still not defined. Can with this layout builder let the list fill a space and just get his height or something ? I really need to set all in hard way ? Thank for your answer – OOM Mar 08 '19 at 17:32
  • Sorry but I don't understand your comment. – Rémi Rousselet Mar 08 '19 at 17:34
  • I don't really understand how to adapt this to my problem. :/ With your way I am finally obliged to define a fixed size according to contraints (like a kind of responsive wesite) if I understand correctly. But what if I want that my widget list fill the whole body ? Je comprends pas vraiment comment adapter ça à mon problème. :/ Avec votre manière je suis obligé au final de définir une taille fixe en fonction de contraintes (comme un genre de site responsive) si je comprends bien. Mais si je veux qu'il remplisse tout le body ? – OOM Mar 08 '19 at 17:45
  • `constraints` represent the available space that the list can take. As such `constraints.biggest` is the size of the whole body. – Rémi Rousselet Mar 08 '19 at 17:48
  • Perfect exactly what i needed. Like that it's even possible to allow percentage like (this widget take that % of the body etc..). Thank you Rémi Rousselet – OOM Mar 08 '19 at 17:54
1

You can deduce the Listview size by subtraction the height of the AppBar for the total screen height. You can get AppBar height by defining it before assignment:

   class _MyHomePageState extends State<MyHomePage> {

   AppBar myBar = AppBar(title: Text(widget.title),);

   @override
   Widget build(BuildContext context) {  
      return Scaffold(
        appBar: myBar,
      )

Then Your Listview height would be :

  var _listHeight = MediaQuery.of(context).size.height - myBar.prefferedSize.height ;

And each letter size would be :

  var _letterHeight = height/27 ;

You should make your letters' sizes less than the above size to provide some spacing between them.

Mazin Ibrahim
  • 7,433
  • 2
  • 33
  • 40
  • 1
    Yes this is working ! (even if its little bit tricky) Problem is that i need to remove all height of all other widget that are on top of it. I mean it will work for this "easy" view but a generic approach should be nice. Thank you – OOM Mar 08 '19 at 17:39
  • well I wish I had one, but I assume all other widgets above a list will have a defined size (you won't have two lists on top of each other, would you?) thus you can generalize this method. – Mazin Ibrahim Mar 08 '19 at 17:51
  • 1
    It's ok with the LayoutBuilder method just above you can directly get the body size and then adapt your component without taking in consideration the AppBar. Thank you. – OOM Mar 08 '19 at 17:55