Search code examples
flutterdartflutter-widgetflutter-imagesinglechildscrollview

How to get size of a child Widget


I have a special requirement to allow for a header widget, usually containing static content to appear at the top of a scroll view. The scroll view should overlap the header widget so that a clip shape can be used for effect. I've achieved this effect by using a stack view with the header widget as the first item in the stack, the scroll view as the top element. The scroll view contains a column with the first child being an empty container of the desired height (the height of the header widget minus the amount of overlap). This achieves the desired effect when passing in a known height as a hard-coded parameter. (NOTE: I tried to accomplish this using a Sliver List, but wasn't able to achieve the desired overlap to meet product requirements.)

The header widget contains an image which is loaded via an API response. The height of the images can vary so I need to determine this at runtime and adjust the UI accordingly. I didn't think this would be a difficult task but so far, I've not found a way to do this. The following two images show the desired effect, the image on the right shows the correct behavior on scrolling up. Note that the scroll view must overlap the header image by the same amount as the radius of the clip.

enter image description here enter image description here

This generates the list. _getComponents provides child widgets for a column contained in the SingleChildScrollView:

  List<Widget> _getComponents(List<Section> sections, BuildContext context, double? height) {
    List<Widget> widgetList = [
      Container(height: 225) // need to obtain correct height here
    ];
    for (int i = 1; i < sections.length; i++) {
      Section section = sections[i];
      if (section.model != null) {
        switch (section.code) {
          case mediaTypeCode:
            if (section.model.runtimeType == MediaModel) {
              widgetList.add(HeaderComponent(section: section));
            }
            break;
          case articleTypeCode:
            if (section.model.runtimeType == ArticleSectionModel) {
              widgetList.add(TitleContentHeader(
                  model: section.model as ArticleSectionModel));
            }
            break;
        }
      }
    }
    return widgetList;
  }

Then in my view widget, the stack is built as follows:

return Container(
  color: Colors.white,
  child: Stack(
    children: [
      _getHeader(sections),
      SingleChildScrollView(
        child: Column(
          children: _getComponents(sections!, context, null),
        ),
      ),
    ],
  ),
);

I need to be able to get the height of the header returned in _getHeader(sections) and pass it to the _getComponents function so that I can determine the correct starting position for the scroll view.

Can anyone offer any insight into this?

Or, can you suggest a plugin that would allow the behavior show in the images above? As mentioned above, Sliver List did not produce the desired effect.

Thanks!


Solution

  • You can get size of a widget using RenderBox :

    
        import 'package:flutter/material.dart';
    
        class WidgetPosition {
          getSizes(GlobalKey key) {
            final RenderBox renderBoxRed = key.currentContext.findRenderObject();
            final sizeRed = renderBoxRed.size;
            // print("SIZE: $sizeRed");
            return [sizeRed.width, sizeRed.height];
          }
    
          getPositions(GlobalKey key) {
            final RenderBox renderBoxRed = key.currentContext.findRenderObject();
            final positionRed = renderBoxRed.localToGlobal(Offset.zero);
            // print("POSITION: $positionRed ");
            return [positionRed.dx, positionRed.dy];
          }
        }