效果gif
定义属性
final tabBarHeight = useRef(42.0); final items = useRef(['产品详情', '购买须知', '服务评价'] .map((e) => Tab( height: 40, text: e, )) .toList()); final tabC = useTabController(initialLength: items.value.length); final scroller = useScrollController(); final isTabClicked = useRef(false); final keys = useRef([ GlobalKey(debugLabel: 'tab1'), GlobalKey(debugLabel: 'tab2'), GlobalKey(debugLabel: 'tab3'), ]);
定义监听
useEffect(() { void tabCL() { if (tabC.indexIsChanging) { isTabClicked.value = true; final keyRenderObject = keys.value[tabC.index].currentContext ?.findAncestorRenderObjectOfType(); scroller.position .ensureVisible(keyRenderObject!, duration: const Duration(milliseconds: 300), curve: Curves.easeIn) .then((value) { isTabClicked.value = false; }); } } void scrL() { if (isTabClicked.value) return; int i = 0; for (; i < keys.value.length; i++) { final keyRenderObject = keys.value[i].currentContext?.findAncestorRenderObjectOfType(); if (keyRenderObject != null) { final offsetY = (keyRenderObject.parentData as SliverPhysicalParentData) .paintOffset .dy; if (offsetY > tabBarHeight.value) { break; } } } tabC.index = i > 0 ? i - 1 : 0; } tabC.addListener(tabCL); scroller.addListener(scrL); return () { tabC.removeListener(tabCL); scroller.removeListener(scrL); tabC.dispose(); scroller.dispose(); }; }, [3]);
每个组件设置Key
CustomScrollView( controller: scroller, slivers: [ SliverAppBar( backgroundColor: Colors.transparent, pinned: true, toolbarHeight: 0, expandedHeight: 380, flexibleSpace: const FlexibleSpaceBar( background: HeaderProductDetail(), ), bottom: PreferredSize( preferredSize: Size.fromHeight(tabBarHeight.value), child: Container( color: Colors.white, child: TabBar( tabs: items.value, controller: tabC, unselectedLabelColor: Colors.grey, indicator: context.extensions.underlineTabIndicator, ), ), ), ), SliverToBoxAdapter( child: Container( key: keys.value[0], height: Screens.height, width: double.infinity, color: Colors.red, child: Text("==============="), ), ), SliverToBoxAdapter( child: Container( key: keys.value[1], height: Screens.height, width: double.infinity, color: Colors.yellow, child: Text("==============="), ), ), SliverToBoxAdapter( child: Container( key: keys.value[2], height: Screens.height, width: double.infinity, color: Colors.blue, child: Text("==============="), ), ) ], )