flutterflutter-sliverflutter-cupertinoflutter-sliverappbarcupertinonavigationbar

How to achieve Cupertino Style Navigation Bar with a cupertino search field inside it


I am developing an iOS application in flutter. I want a navigation bar which can be expandable. On expand there should be large title on left side and on collapse same title should be on top center. This thing is possible with CupertinoSliverNavigationBar but I want to add a search field under the large title which should only appear when navigation bar should be expanded and on scroll up, first search bar should be scrolled up and then CupertinoSliverNavigationBar. This is default behaviour in many iOS applications. Let me show an example

Default IOS Scrolling

enter image description here

You can notice in example when scroll up then first height of search bar gets decreases then navigation bar collapses and when scroll down then first navigation bar expands then height of search bar increases. This is what I achieved yet Achieved Result

This is my code

CustomScrollView(
                          physics:  const AlwaysScrollableScrollPhysics(),
                          controller: _scrollController,

                          slivers: <Widget> [
                            const CupertinoSliverNavigationBar(
                              largeTitle: Text('Products'),
                              stretch: true,
                              //backgroundColor: Colors.white,
                              border: Border(),

                              trailing: Icon(CupertinoIcons.add,color: CupertinoColors.systemBlue,size: 24,),
                            ),
                            SliverToBoxAdapter(
                              child: Padding(
                                padding: const EdgeInsets.symmetric(horizontal: 15),
                                child: CupertinoSearchTextField(
                                
                                  controller:  _controller,

                                  onSubmitted: (String value) {
                                  },
                                ),
                              ),
                            ),
                            SliverFillRemaining(
                              child: _controller.text.isNotEmpty?
                              paymentList(state.productDataSearch!,state):
                              paymentList(state.productData!,state),
                            ),
                          ],
                        ),

[1]: https://i.sstatic.net/nfARA.png


Solution

  • I achieved this by using NotificationListener and change the height of textfield according to the position of scroll

         return NotificationListener<ScrollNotification>(
                                  onNotification: (ScrollNotification scrollInfo) {
    
                                    if (scrollInfo is ScrollUpdateNotification) {
    
                                      if (scrollInfo.metrics.pixels > previousScrollPosition) {
                                        //print("going up ${scrollInfo.metrics.pixels}");
                                        ///up
                                        if(isVisibleSearchBar > 0 && scrollInfo.metrics.pixels > 0){
                                          setState(() {
                                            isVisibleSearchBar = (40 - scrollInfo.metrics.pixels) >= 0?(40 - scrollInfo.metrics.pixels):0;
                                          });
                                        }
                                      }
                                      else if (scrollInfo.metrics.pixels <= previousScrollPosition) {
                                        //print("going down ${scrollInfo.metrics.pixels}");
                                        ///down
                                        if(isVisibleSearchBar < 40 && scrollInfo.metrics.pixels >= 0 && scrollInfo.metrics.pixels <= 40){
                                          setState(() {
                                            isVisibleSearchBar = (40 - scrollInfo.metrics.pixels) <= 40?(40 - scrollInfo.metrics.pixels):40;
                                          });
                                        }
                                      }
                                      setState(() {
                                        previousScrollPosition = scrollInfo.metrics.pixels;
                                      });
                                    }
                                    else if (scrollInfo is ScrollEndNotification) {
                                      print("on edn isVisibleSearchBar $isVisibleSearchBar");
                                      Future.delayed(Duration.zero, () {
                                        if(isVisibleSearchBar < 20 && isVisibleSearchBar > 0){
    
                                          setState(() {
                                            isVisibleSearchBar = 0;
                                            _scrollController.animateTo(60, duration: const Duration(milliseconds: 200), curve: Curves.ease);
                                          });
    
                                        }
                                        else if(isVisibleSearchBar >= 20 && isVisibleSearchBar <= 40){
                                          setState(() {
                                            isVisibleSearchBar = 40;
                                            _scrollController.animateTo(0, duration: const Duration(milliseconds: 200), curve: Curves.ease);
                                          });
                                        }
                                      });
                                    }
                                    return true;
                                  },
                                  child: CustomScrollView(
                                    physics:  const AlwaysScrollableScrollPhysics(),
                                    controller: _scrollController,
                                    anchor:0.06,
    
                                    slivers: <Widget> [
    
                                      CupertinoSliverNavigationBar(
                                        largeTitle: Column(
                                          crossAxisAlignment: CrossAxisAlignment.start,
                                          children: [
                                            const Text('Products'),
                                            AnimatedContainer(
    
                                              duration: const Duration(milliseconds: 200),
                                              height: isVisibleSearchBar,
                                              child: Padding(
                                                padding: const EdgeInsets.only(right: 15,top: 3),
                                                child: CupertinoSearchTextField(
                                                  onChanged: (val){
                                                    print("client $val");
                                                    if(val.isNotEmpty){
                                                      EasyDebounce.debounce('search_name_debounce', const Duration(milliseconds: 300), () {
                                                        productBloc.add(SearchPayment(val));
                                                        setState(() {});
                                                      });
                                                    }
                                                    else{
                                                      EasyDebounce.debounce('search_name_debounce', const Duration(milliseconds: 300), () {
                                                        productBloc.add(const SetInitialSearch());
                                                        setState(() {});
                                                      });
                                                    }
                                                  },
                                                  itemSize:isVisibleSearchBar/2,
                                                  prefixIcon: AnimatedOpacity(
                                                    duration: const Duration(milliseconds: 200),
                                                    opacity: isVisibleSearchBar/40 > 1?1:
                                                     isVisibleSearchBar/40 < 0?0:isVisibleSearchBar/40,
                                                    child: const Icon(CupertinoIcons.search),
                                                  ),
                                                  controller:  _controller,
                                                  onSubmitted: (String value) {
                                                  },
                                                ),
                                              ),
                                            ),
                                          ],
                                        ),
                                        stretch: true,
                                        middle:  const Text('Products'),
                                        alwaysShowMiddle: false,
                                        backgroundColor: Colors.white,
                                        trailing: const Icon(CupertinoIcons.add,color: CupertinoColors.activeBlue,size: 24,),
                                      ),
    
    
    
                                      SliverToBoxAdapter(
                                        child: SafeArea(
                                          top: false,
                                          child: Scrollbar(
                                            child: _controller.text.isNotEmpty?
                                            paymentList(state.productDataSearch!,state):
                                            paymentList(state.productData!,state),
                                          ),
                                        ),
                                      ),
                                    ],
                                  ),
                                );