1

If I scroll down, the collapsed app bar becomes visible and the first child is also visible. That's good. However, if I suddenly change the scrolling direction to up, even though the app bar is still collapsed, the second child is displayed. Why does this happen? Which part of the code might be causing the problem?

CODE:

class SABT extends StatefulWidget {
  final Widget firstChild;
  final Widget secondChild;

  const SABT({
    Key? key,
    required this.firstChild,
    required this.secondChild,
  }) : super(key: key);

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

class _SABTState extends State<SABT> {
  ScrollPosition? _position;
  bool _visibleFirst = true;

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

  @override
  void didChangeDependencies() {
    super.didChangeDependencies();

    _removeListener();
    _addListener();
  }

  void _addListener() {
    _position = Scrollable.of(context)?.position;
    _position?.addListener(_positionListener);
    _positionListener();
  }

  void _removeListener() {
    _position?.removeListener(_positionListener);
  }

  void _positionListener() {
    final FlexibleSpaceBarSettings? settings =
        context.dependOnInheritedWidgetOfExactType<FlexibleSpaceBarSettings>();

    bool visibleFirst =
        settings == null || settings.currentExtent <= settings.minExtent;

    if (_visibleFirst != visibleFirst) {
      setState(() {
        _visibleFirst = visibleFirst;
      });
    }
  }

  @override
  Widget build(BuildContext context) {
    return Visibility(
      visible: _visibleFirst,
      child: widget.firstChild,
      replacement: Visibility(
        visible: !_visibleFirst,
        child: widget.secondChild,
      ),
    );
  }
}
          SliverAppBar(
           pinned: true,
           elevation: 0,
           stretch: true,
            expandedHeight: 500,
title: SABT(firstChild: Text("first title"),secondChild: Text("second title")),
            flexibleSpace: FlexibleSpaceBar(
              background: Container(
                color: Colors.purple,
              ),
            ),
          ),

I have examined the code for the SABT widget and tested it in my Flutter project. To troubleshoot the issue, I checked the scroll position listener and the visibility logic. Additionally, I reviewed the implementation of the SliverAppBar that contains the SABT widget. However, despite my efforts, I couldn't identify the exact cause of the problem.

I was expecting the SABT widget to maintain the visibility of the first child when the scroll direction is suddenly changed to up, even if the SliverAppBar remains collapsed. However, currently, when I change the scroll direction to up, the second child is unexpectedly displayed instead. I would like the SABT widget to consistently show the first child when the scroll direction changes, as long as the SliverAppBar is still collapsed.

2
  • Number of SABTs used: 11. Number of times SABT is defined: ZERO. And the googles didn't help. Commented Jun 28, 2023 at 14:34
  • So it has been a week. Are you still not going to explain what a SABT widget is? Commented Jul 5, 2023 at 18:42

2 Answers 2

1

what Flutter version and what kind of test device are you using?

I could not reproduce the issue with a simple CustomScrollView on the newest Flutter version with an android device:

return CustomScrollView(
 physics: const BouncingScrollPhysics(),
 reverse: false,
 slivers: <Widget>[
  SliverAppBar(
    pinned: true,
    elevation: 0,
    stretch: true,
    expandedHeight: 500,
    title: const SABT(firstChild: Text("first title"), secondChild: Text("second title")),
    flexibleSpace: FlexibleSpaceBar(background: Container(color: Colors.purple)),
  ),
  SliverList(
    delegate: SliverChildBuilderDelegate(
      (BuildContext context, int index) => ListTile(title: Text('Item #$index')),
      childCount: 30,
    ),
  ),
 ],
);

You can also convert your SABT into a StatelessWidget and remove the dependency on the scroll position.

class SABT extends StatelessWidget {
  final Widget firstChild;
  final Widget secondChild;

  const SABT({
    Key? key,
    required this.firstChild,
    required this.secondChild,
  }) : super(key: key);

  @override
  Widget build(BuildContext context) {
    final FlexibleSpaceBarSettings? settings = context.dependOnInheritedWidgetOfExactType<FlexibleSpaceBarSettings>();
    final bool visibleFirst = settings == null || settings.currentExtent <= settings.minExtent;
    return Visibility(
      visible: visibleFirst,
      replacement: Visibility(
        visible: !visibleFirst,
        child: secondChild,
      ),
      child: firstChild,
    );
  }
}
0

In replacement you dont have to again add visibility

replacement:  widget.secondChild,

Replacement is displayed when the first child is hidden

1
  • Thank you for your suggestion. I tried using replacement: widget.secondChild, as you mentioned, but unfortunately, it didn't resolve the issue.
    – gaith
    Commented Jun 29, 2023 at 13:27

Not the answer you're looking for? Browse other questions tagged or ask your own question.