You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Flutter实现带Cupertino搜索框的可展开iOS风格导航栏

需求与当前实现

我正在用Flutter开发iOS应用,需要一个符合以下要求的可展开导航栏:

  • 展开状态:左侧显示大标题,下方带搜索框
  • 收起状态:标题居中
  • 滚动行为遵循iOS默认逻辑:向上滚动时先收起搜索框,再折叠导航栏;向下滚动时先展开导航栏,再显示搜索框

目前用CupertinoSliverNavigationBar实现了基础的展开/收起导航栏效果,但搜索框是单独的SliverToBoxAdapter,滚动时无法实现上述联动逻辑。当前代码如下:

CustomScrollView(
  physics: const AlwaysScrollableScrollPhysics(),
  controller: _scrollController,
  slivers: <Widget> [
    const CupertinoSliverNavigationBar(
      largeTitle: Text('Products'),
      stretch: true,
      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),
    ),
  ],
),

已实现效果:导航栏可展开/收起,但搜索框和导航栏滚动无联动,向上滚动时两者同时收起;向下滚动时同时展开。
目标效果:iOS原生滚动联动逻辑,先处理搜索框的显示/隐藏,再处理导航栏的展开/折叠。

解决方案

要实现这种iOS原生的滚动联动逻辑,需要把搜索框整合到导航栏的可展开区域,并通过监听滚动偏移控制其显示状态,配合CupertinoSliverNavigationBar的原生行为。具体实现代码如下:

class _ProductPageState extends State<ProductPage> {
  final ScrollController _scrollController = ScrollController();
  final TextEditingController _controller = TextEditingController();
  bool _isNavBarExpanded = true;
  final double _searchBarMaxHeight = 50;
  double _searchBarHeight = 50;

  @override
  void initState() {
    super.initState();
    _scrollController.addListener(_handleScroll);
  }

  @override
  void dispose() {
    _scrollController.removeListener(_handleScroll);
    _scrollController.dispose();
    _controller.dispose();
    super.dispose();
  }

  void _handleScroll() {
    final double navBarCollapseThreshold = MediaQuery.of(context).padding.top + 44;
    final double scrollOffset = _scrollController.offset;

    setState(() {
      _isNavBarExpanded = scrollOffset < navBarCollapseThreshold;

      if (scrollOffset <= 0) {
        _searchBarHeight = _searchBarMaxHeight;
      } else if (scrollOffset < navBarCollapseThreshold) {
        _searchBarHeight = _searchBarMaxHeight - (scrollOffset / navBarCollapseThreshold) * _searchBarMaxHeight;
      } else {
        _searchBarHeight = 0;
      }
    });
  }

  @override
  Widget build(BuildContext context) {
    return CupertinoPageScaffold(
      child: CustomScrollView(
        physics: const AlwaysScrollableScrollPhysics(),
        controller: _scrollController,
        slivers: <Widget>[
          CupertinoSliverNavigationBar(
            largeTitle: _isNavBarExpanded
                ? Column(
                    crossAxisAlignment: CrossAxisAlignment.start,
                    children: [
                      const Text('Products'),
                      SizedBox(
                        height: _searchBarHeight,
                        child: Padding(
                          padding: const EdgeInsets.only(top: 8),
                          child: CupertinoSearchTextField(
                            controller: _controller,
                            onSubmitted: (String value) {},
                          ),
                        ),
                      ),
                    ],
                  )
                : null,
            middle: const Text('Products'),
            stretch: true,
            border: const Border(),
            trailing: const Icon(CupertinoIcons.add, color: CupertinoColors.systemBlue, size: 24),
          ),
          SliverFillRemaining(
            child: _controller.text.isNotEmpty
                ? paymentList(state.productDataSearch!, state)
                : paymentList(state.productData!, state),
          ),
        ],
      ),
    );
  }
}

关键逻辑说明

  • 滚动监听:通过ScrollController捕获滚动偏移,计算导航栏展开状态和搜索框高度
  • 动态搜索框:将搜索框作为largeTitle的一部分,根据滚动偏移调整高度,实现“先收起搜索框再折叠导航栏”的顺序
  • 导航栏状态切换:导航栏收起时,middle属性显示居中标题;展开时,largeTitle显示左侧大标题和动态高度的搜索框

内容的提问来源于stack exchange,提问作者Umar Ghaffar

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.24 17:07:46