flutterflutter-animation

Flutter: Implementing Filters in AppBar with Scroll and Hide Functionality


I need to implement filters at the top of the screen. The idea is that when you scroll down, the filters should disappear, but the title and leading widget should remain visible. Additionally, when scrolling up, the filters should reappear. Does anyone have any suggestions on how to achieve this, what is the best use for this for this feature?


Solution

  • you achive this using ScrollController to detect scroll direction and a combination of SliverAppBar and SliverPersistentHeader for the layout.

    import 'package:flutter/material.dart';
    
    class ScrollableFiltersPage extends StatefulWidget {
      @override
      _ScrollableFiltersPageState createState() => _ScrollableFiltersPageState();
    }
    
    class _ScrollableFiltersPageState extends State<ScrollableFiltersPage> {
      final ScrollController _scrollController = ScrollController();
      bool _showFilters = true;
      double _lastOffset = 0;
    
      @override
      void initState() {
        super.initState();
        _scrollController.addListener(() {
          if (_scrollController.offset > _lastOffset && _showFilters) {
            setState(() => _showFilters = false); // Scrolling down
          } else if (_scrollController.offset < _lastOffset && !_showFilters) {
            setState(() => _showFilters = true); // Scrolling up
          }
          _lastOffset = _scrollController.offset;
        });
      }
    
      @override
      Widget build(BuildContext context) {
        return Scaffold(
          body: CustomScrollView(
            controller: _scrollController,
            slivers: [
              SliverAppBar(
                pinned: true,
                title: Text('Title'),
                leading: Icon(Icons.menu),
              ),
              SliverPersistentHeader(
                pinned: true,
                delegate: _FiltersDelegate(
                  showFilters: _showFilters,
                  child: Container(
                    color: Colors.blueGrey,
                    height: 50,
                    child: Row(
                      mainAxisAlignment: MainAxisAlignment.spaceAround,
                      children: [
                        TextButton(onPressed: () {}, child: Text("Filter 1")),
                        TextButton(onPressed: () {}, child: Text("Filter 2")),
                        TextButton(onPressed: () {}, child: Text("Filter 3")),
                      ],
                    ),
                  ),
                ),
              ),
              SliverList(
                delegate: SliverChildBuilderDelegate(
                  (context, index) => ListTile(title: Text('Item $index')),
                  childCount: 50,
                ),
              ),
            ],
          ),
        );
      }
    }
    
    
    class _FiltersDelegate extends SliverPersistentHeaderDelegate {
      final bool showFilters;
      final Widget child;
    
      _FiltersDelegate({required this.showFilters, required this.child});
    
      @override
      Widget build(BuildContext context, double shrinkOffset, bool overlapsContent) {
        return AnimatedOpacity(
          duration: Duration(milliseconds: 200),
          opacity: showFilters ? 1.0 : 0.0,
          child: child,
        );
      }
    
      @override
      double get maxExtent => 50.0;
      @override
      double get minExtent => 50.0;
      @override
      bool shouldRebuild(covariant _FiltersDelegate oldDelegate) =>
          showFilters != oldDelegate.showFilters || child != oldDelegate.child;
    }
    

    I HOPE THIS IS HELP YOU. THANK YOU:)