skip to Main Content

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

Answers


  1. In replacement you dont have to again add visibility

    replacement:  widget.secondChild,
    

    Replacement is displayed when the first child is hidden

    Login or Signup to reply.
  2. 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,
        );
      }
    }
    
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search