import 'package:flutter/material.dart'; import 'package:get/get.dart'; import 'package:ftrecruiter/comm/utils/log_utils.dart'; import 'package:ftrecruiter/comm/widget/load_state_layout.dart'; import 'package:ftrecruiter/comm/widget/my_load_image.dart'; import 'package:ftrecruiter/modules/zdemo/page_four.dart'; import 'package:ftrecruiter/modules/zdemo/page_one.dart'; import 'package:ftrecruiter/modules/zdemo/page_three.dart'; import 'package:ftrecruiter/modules/zdemo/page_two.dart'; class DemoScroll1Page extends StatelessWidget { const DemoScroll1Page({Key? key}) : super(key: key); @override Widget build(BuildContext context) { final _tabs = ['猜你喜欢', '今日特价', '发现更多']; // 构建 tabBar return DefaultTabController( length: _tabs.length, // This is the number of tabs. child: Scaffold( body: NestedScrollView( headerSliverBuilder: (BuildContext context, bool innerBoxIsScrolled) { return [ SliverOverlapAbsorber( handle: NestedScrollView.sliverOverlapAbsorberHandleFor(context), sliver: SliverAppBar( title: const Text('商城'), floating: false, snap: false, elevation: 0.0, forceElevated: innerBoxIsScrolled, pinned: true, ), ), SliverToBoxAdapter( child: Container( alignment: Alignment.center, width: double.infinity, height: 191, child: MyLoadImage("https://i04piccdn.sogoucdn.com/a35bde4b5756167a",width: 340, height: 191), ), ), SliverPersistentHeader( pinned: true, // 固定在顶部 delegate: SliverHeaderDelegate.fixedHeight( //固定高度 height: 50, child: Container( color: Colors.pink, child: TabBar( tabs: _tabs.map((String name) => Tab(text: name)).toList(), ), ), ), ), ]; }, body: TabBarView( children: _tabs.map((String name) { return Builder( builder: (BuildContext context) { return CustomScrollView( key: PageStorageKey(name), slivers: [ SliverOverlapInjector( handle: NestedScrollView.sliverOverlapAbsorberHandleFor(context), ), SliverPadding( padding: const EdgeInsets.all(8.0), sliver: buildSliverList(50), ), ], ); }, ); }).toList(), ), ), ), ); } // 构建固定高度的SliverList,count为列表项属相 Widget buildSliverList([int count = 5]) { return SliverFixedExtentList( itemExtent: 50, delegate: SliverChildBuilderDelegate( (context, index) { return ListTile(title: Text('$index')); }, childCount: count, ), ); } } typedef SliverHeaderBuilder = Widget Function( BuildContext context, double shrinkOffset, bool overlapsContent); class SliverHeaderDelegate extends SliverPersistentHeaderDelegate { // child 为 header SliverHeaderDelegate({ required this.maxHeight, this.minHeight = 0, required Widget child, }) : builder = ((a, b, c) => child), assert(minHeight <= maxHeight && minHeight >= 0); //最大和最小高度相同 SliverHeaderDelegate.fixedHeight({ required double height, required Widget child, }) : builder = ((a, b, c) => child), maxHeight = height, minHeight = height; //需要自定义builder时使用 SliverHeaderDelegate.builder({ required this.maxHeight, this.minHeight = 0, required this.builder, }); final double maxHeight; final double minHeight; final SliverHeaderBuilder builder; @override Widget build( BuildContext context, double shrinkOffset, bool overlapsContent, ) { Widget child = builder(context, shrinkOffset, overlapsContent); //测试代码:如果在调试模式,且子组件设置了key,则打印日志 assert(() { if (child.key != null) { print('${child.key}: shrink: $shrinkOffset,overlaps:$overlapsContent'); } return true; }()); // 让 header 尽可能充满限制的空间;宽度为 Viewport 宽度, // 高度随着用户滑动在[minHeight,maxHeight]之间变化。 return SizedBox.expand(child: child); } @override double get maxExtent => maxHeight; @override double get minExtent => minHeight; @override bool shouldRebuild(SliverHeaderDelegate old) { return old.maxExtent != maxExtent || old.minExtent != minExtent; } }