如何用CupertinoSliverNavigationBar实现iOS健康App Browse页头部UI?
你不需要用两个CupertinoSliverNavigationBar——第二个导航栏的空白是因为它默认保留了大标题区域的高度,哪怕设置largeTitle: SizedBox.shrink()也无法消除。正确的做法是用一个导航栏承载大标题,再把搜索栏做成固定在顶部的独立Sliver组件,具体实现如下:
CustomScrollView( slivers: [ // 顶部大标题导航栏 const CupertinoSliverNavigationBar( backgroundColor: CupertinoColors.black, largeTitle: Text('Browse'), stretch: true, ), // 固定在顶部的搜索栏 SliverPersistentHeader( pinned: true, delegate: _SearchHeaderDelegate( searchField: CupertinoSearchTextField( backgroundColor: CupertinoColors.darkBackgroundGray, placeholder: 'Search', placeholderStyle: TextStyle(color: CupertinoColors.systemGrey), prefixIcon: Icon(CupertinoIcons.search, color: CupertinoColors.systemGrey), ), ), ), // 列表内容 SliverList( delegate: SliverChildBuilderDelegate( (context, index) => Container( height: 60, color: index % 2 == 0 ? CupertinoColors.systemGrey6 : CupertinoColors.white, alignment: Alignment.center, child: Text('List Item $index'), ), childCount: 20, ), ), ], ); // 自定义SliverPersistentHeader代理类 class _SearchHeaderDelegate extends SliverPersistentHeaderDelegate { final Widget searchField; _SearchHeaderDelegate({required this.searchField}); @override Widget build(BuildContext context, double shrinkOffset, bool overlapsContent) { return Container( color: CupertinoColors.black, padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 8), child: searchField, ); } @override double get maxExtent => 56; // 搜索栏的高度,可根据需要调整 @override double get minExtent => 56; // 固定高度,滚动时不收缩 @override bool shouldRebuild(covariant _SearchHeaderDelegate oldDelegate) { return oldDelegate.searchField != searchField; } }
关键说明:
- 用
SliverPersistentHeader替代第二个CupertinoSliverNavigationBar,通过pinned: true让搜索栏滚动时固定在顶部,和iOS健康App的交互效果一致。 - 自定义代理类
_SearchHeaderDelegate控制搜索栏的高度和样式,背景色和导航栏保持统一,视觉上无缝衔接。 - 这种方式彻底避免了第二个导航栏带来的大标题空白问题,同时满足UI需求。
内容的提问来源于stack exchange,提问作者hgJang
相关产品推荐
相关产品推荐

