Bram  Vanbilsen
Bram Vanbilsen

Reputation: 6505

Event when ScrollController get attached

I'm trying to display a widget once I have info about the max scroll extent. I can find that number if I assign an instance of ScrollController to the controller property of a scrollable widget.

My problem is that the ScrollController gets attached to the scrollable widget during the build, so I can not use the max scroll extent number before the first build. Thus what I was trying to do is display an empty Container in the first build and then switch that empty Container with the widget I actually want. Something like this:

    _scrollController.positions.length == 0 ? new Container() : new Align(
      alignment: Alignment.center,
      child: new Container(
        width: constraints.maxWidth,
        height: 50.0,
        color: Colors.black,
      )
    )

Now this does not work of course because _scrollController.positions.length will be 0 at the beginning and nowhere do I call setState when this value changes (when the controller gets attached).
So my question: Is there a place where I can get notified whenever the ScrollController gets attached to a scrollable widget? Or is there a better approach for this?

Upvotes: 4

Views: 1836

Answers (1)

Marcelo Glasberg
Marcelo Glasberg

Reputation: 30879

If the scrollable is widget.child.

@override
Widget build(BuildContext context) {
  return new NotificationListener<ScrollNotification>(
    onNotification: _handleScrollNotification,
    child: widget.child,
  );
}

bool _handleScrollNotification(ScrollNotification notification) {
  if (notification is ScrollUpdateNotification || notification is OverscrollNotification) {
    widget.child.update(notification.metrics);
  }
return false;
}

@override
void initState() {
  super.initState();
  WidgetsBinding.instance.addPostFrameCallback((_) => afterFirstLayout(context));
}

void afterFirstLayout(BuildContext context) {
  applyInitialScrollPosition();
}

void applyInitialScrollPosition() {
  ScrollController scrollControler = widget.child.controller;
  ScrollPosition position = scrollControler.position;
  ScrollNotification notification = ScrollUpdateNotification(
      metrics: FixedScrollMetrics(
          minScrollExtent: position.minScrollExtent,
          maxScrollExtent: position.maxScrollExtent,
          pixels: position.pixels,
          viewportDimension: position.viewportDimension,
          axisDirection: position.axisDirection),
      context: null,
      scrollDelta: 0.0);
_handleScrollNotification(notification);
}

The child must extends ChangeNotifier and has an update method:

void update(ScrollMetrics metrics) {
  assert(metrics != null);
  _lastMetrics = metrics; // Save the metrics.
  notifyListeners();
}

All this only works if a scroll controller has explicitly been defined for the scrollable (widget.child).

Upvotes: 3

Related Questions