Search code examples
flutterdartuser-interfaceflutter-animation

How can I hide the TextField when I scroll down and display it again when I scroll up?


I can't figure out how to do it I found a couple of different ways, but they don't quite work for me.

I tried to use SilverAppBar, but I couldn't do what I wanted to do. Now I use the hidable: ^1.0.3 library
and with it I got what I wanted but when I scroll down TextField disappears and doesn't appear when I scroll up My code

class HomeScreen extends StatefulWidget {
  HomeScreen({Key? key}) : super(key: key);

  @override
  State<HomeScreen> createState() => _HomeScreenState();
}

class _HomeScreenState extends State<HomeScreen> {
  final ScrollController scrollController = ScrollController();

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      backgroundColor: Colors.black,
      appBar: buildAppBar(),
      body: Stack(
        children: [
          Container(
            margin: EdgeInsets.symmetric(horizontal: 20),
            child: Column(
              children: [
                SizedBox(height: 15),
                Hidable(
                    controller: scrollController,
                    wOpacity: false,
                    child: searchBox()),
                SizedBox(height: 15),
                Expanded(
                  child: GridView.count(
                    physics: BouncingScrollPhysics(),
                    crossAxisCount: 2,
                    children: [
                      GridItem(),
                      GridItem(),
                      GridItem(),
                      GridItem(),
                      GridItem(),
                      GridItem(),
                      GridItem(),
                      GridItem(),
                      GridItem(),
                      GridItem(),
                      GridItem(),
                      GridItem(),
                      GridItem(),
                      GridItem(),
                      GridItem(),
                      GridItem(),
                      GridItem(),
                      GridItem(),
                      GridItem(),
                      GridItem(),
                      GridItem(),
                      GridItem(),
                    ],
                  ),
                ),
              ],
            ),
          ),
          Positioned(
            bottom: 20,
            right: 20,
            child: Container(
              padding: EdgeInsets.symmetric(vertical: 5),
              child: ElevatedButton(
                onPressed: () {},
                style: ElevatedButton.styleFrom(
                  shape: RoundedRectangleBorder(
                    borderRadius: BorderRadius.circular(30),
                  ),
                  primary: AppStyle.iconColor,
                  minimumSize: Size(60, 60),
                  elevation: 10,
                ),
                child: Text(
                  '+',
                  style: TextStyle(color: Colors.white, fontSize: 40),
                ),
              ),
            ),
          ),
        ],
      ),
    );
  }

  Container searchBox() {
    return Container(
      margin: EdgeInsets.symmetric(horizontal: 15),
      decoration: BoxDecoration(
        color: AppStyle.itemColor,
        borderRadius: BorderRadius.circular(20),
      ),
      child: TextField(
        decoration: InputDecoration(
          contentPadding: EdgeInsets.all(0),
          prefixIcon: Icon(
            Icons.search,
            color: Colors.grey,
            size: 20,
          ),
          prefixIconConstraints: BoxConstraints(
            maxHeight: 20,
            minWidth: 25,
          ),
          border: InputBorder.none,
          hintText: "Search",
          hintStyle: TextStyle(color: Colors.grey),
        ),
      ),
    );
  }

  AppBar buildAppBar() {
    return AppBar(
      backgroundColor: Colors.black,
      elevation: 0.0,
      title: Row(
        mainAxisAlignment: MainAxisAlignment.center,
        children: [
          Padding(
            padding: const EdgeInsets.symmetric(horizontal: 20),
            child: Icon(Icons.square, size: 35),
          ),
          Padding(
            padding: const EdgeInsets.symmetric(horizontal: 20),
            child: Icon(
              Icons.square,
              size: 35,
            ),
          ),
        ],
      ),
      centerTitle: true,
    );
  }
}

Solution

  • You can check the scroll direction like, don't need to have extra package.

      isVisible = scrollController.position.userScrollDirection ==
              ScrollDirection.reverse;
    
    class HomeScreen extends StatefulWidget {
      HomeScreen({Key? key}) : super(key: key);
    
      @override
      State<HomeScreen> createState() => _HomeScreenState();
    }
    
    class _HomeScreenState extends State<HomeScreen> {
      bool isVisible = true;
      late final ScrollController scrollController = ScrollController()
        ..addListener(() {
          isVisible = scrollController.position.userScrollDirection ==
              ScrollDirection.reverse;
    
          setState(() {});
        });
    
      @override
      void dispose() {
        scrollController.dispose();
        super.dispose();
      }
    
      @override
      Widget build(BuildContext context) {
        return Scaffold(
          backgroundColor: Colors.black,
          appBar: buildAppBar(),
          body: Stack(
            children: [
              Container(
                margin: EdgeInsets.symmetric(horizontal: 20),
                child: Column(
                  children: [
                    SizedBox(height: 15),
                    SizedBox(height: 15),
                    Expanded(
                      child: GridView.count(
                        controller: scrollController,
                        physics: BouncingScrollPhysics(),
                        crossAxisCount: 2,
                        children: [
                          ...List.generate(
                            33,
                            (index) => Container(
                              child: Center(
                                child: Text(
                                  'Item $index',
                                  style: TextStyle(
                                    color: Colors.white,
                                    fontSize: 20,
                                  ),
                                ),
                              ),
                            ),
                          ),
                        ],
                      ),
                    ),
                  ],
                ),
              ),
              add_button(),
              AnimatedPositioned(
                top: isVisible ? -50 : 0,
                left: 0,
                right: 0,
                duration: Duration(seconds: 1),
                child: searchBox(),
              ),
            ],
          ),
        );
      }
    
      Positioned add_button() {
        return Positioned(
          bottom: 20,
          right: 20,
          child: Container(
            padding: EdgeInsets.symmetric(vertical: 5),
            child: ElevatedButton(
              onPressed: () {},
              style: ElevatedButton.styleFrom(
                shape: RoundedRectangleBorder(
                  borderRadius: BorderRadius.circular(30),
                ),
                // primary: AppStyle.iconColor,
                minimumSize: Size(60, 60),
                elevation: 10,
              ),
              child: Text(
                '+',
                style: TextStyle(color: Colors.white, fontSize: 40),
              ),
            ),
          ),
        );
      }
    
      Container searchBox() {
        return Container(
          margin: EdgeInsets.symmetric(horizontal: 15),
          decoration: BoxDecoration(
            // color: AppStyle.itemColor,
            borderRadius: BorderRadius.circular(20),
          ),
          child: TextField(
            decoration: InputDecoration(
              contentPadding: EdgeInsets.all(0),
              prefixIcon: Icon(
                Icons.search,
                color: Colors.grey,
                size: 20,
              ),
              prefixIconConstraints: BoxConstraints(
                maxHeight: 20,
                minWidth: 25,
              ),
              border: InputBorder.none,
              hintText: "Search",
              hintStyle: TextStyle(color: Colors.grey),
            ),
          ),
        );
      }
    
      AppBar buildAppBar() {
        return AppBar(
          backgroundColor: Colors.black,
          elevation: 0.0,
          title: Row(
            mainAxisAlignment: MainAxisAlignment.center,
            children: [
              Padding(
                padding: const EdgeInsets.symmetric(horizontal: 20),
                child: Icon(Icons.square, size: 35),
              ),
              Padding(
                padding: const EdgeInsets.symmetric(horizontal: 20),
                child: Icon(
                  Icons.square,
                  size: 35,
                ),
              ),
            ],
          ),
          centerTitle: true,
        );
      }
    }
    

    To have only visible on top

      bool isVisible = true;
      late final ScrollController scrollController = ScrollController()
        ..addListener(() {
          // isVisible = scrollController.position.userScrollDirection ==
          //     ScrollDirection.reverse;
    
          // only visible on top
          isVisible = scrollController.offset < 100;
    
          setState(() {});
        });
    

    And

    AnimatedPositioned(
      top: isVisible ? 50 : -50,
      left: 0,
      right: 0,
      duration: Duration(seconds: 1),
      child: searchBox(),
    ),