flutter NestedScrollView 与其body中CustomScrollView滑动冲突解决

import 'package:flutter/material.dart'; import 'package:flutter_screenutil/flutter_screenutil.dart'; const String _kGalleryAssetsPackage = 'flutter_gallery_assets'; class _Page { _Page({this.label}); final String label; String get id => label[0]; @override String toString() => '$runtimeType("$label")'; }class _CardData { const _CardData({this.title, this.imageAsset, this.imageAssetPackage}); final String title; final String imageAsset; final String imageAssetPackage; }final Map<_Page, List<_CardData>> _allPages = <_Page, List<_CardData>>{ new _Page(label: 'LEFT'): <_CardData>[ const _CardData( title: 'Vintage Bluetooth Radio', imageAsset: 'shrine/products/radio.png', imageAssetPackage: _kGalleryAssetsPackage, ), const _CardData( title: 'Sunglasses', imageAsset: 'shrine/products/sunnies.png', imageAssetPackage: _kGalleryAssetsPackage, ), const _CardData( title: 'Clock', imageAsset: 'shrine/products/clock.png', imageAssetPackage: _kGalleryAssetsPackage, ), const _CardData( title: 'Red popsicle', imageAsset: 'shrine/products/popsicle.png', imageAssetPackage: _kGalleryAssetsPackage, ), const _CardData( title: 'Folding Chair', imageAsset: 'shrine/products/lawn_chair.png', imageAssetPackage: _kGalleryAssetsPackage, ), const _CardData( title: 'Green comfort chair', imageAsset: 'shrine/products/chair.png', imageAssetPackage: _kGalleryAssetsPackage, ), const _CardData( title: 'Old Binoculars', imageAsset: 'shrine/products/binoculars.png', imageAssetPackage: _kGalleryAssetsPackage, ), const _CardData( title: 'Teapot', imageAsset: 'shrine/products/teapot.png', imageAssetPackage: _kGalleryAssetsPackage, ), const _CardData( title: 'Blue suede shoes', imageAsset: 'shrine/products/chucks.png', imageAssetPackage: _kGalleryAssetsPackage, ), ], //new _Page(label: 'RIGHT'): <_CardData>[ //const _CardData( //title: 'Beachball', //imageAsset: 'shrine/products/beachball.png', //imageAssetPackage: _kGalleryAssetsPackage, //), //const _CardData( //title: 'Dipped Brush', //imageAsset: 'shrine/products/brush.png', //imageAssetPackage: _kGalleryAssetsPackage, //), //const _CardData( //title: 'Perfect Goldfish Bowl', //imageAsset: 'shrine/products/fish_bowl.png', //imageAssetPackage: _kGalleryAssetsPackage, //), //], }; class _CardDataItem extends StatelessWidget { const _CardDataItem({this.page, this.data}); static const double height = 272.0; final _Page page; final _CardData data; @override Widget build(BuildContext context) { return new Card( child: new Padding( padding: const EdgeInsets.all(16.0), child: new Column( crossAxisAlignment: CrossAxisAlignment.stretch, mainAxisAlignment: MainAxisAlignment.start, children: [ new Align( alignment: page.id == 'L' ? Alignment.centerLeft : Alignment.centerRight, child: new CircleAvatar(child: new Text('${page.id}')), ), new SizedBox( width: 144.0, height: 144.0, child: new Image.asset( data.imageAsset, package: data.imageAssetPackage, fit: BoxFit.contain, ), ), new Center( child: new Text( data.title, style: Theme.of(context).textTheme.title, ), ), ], ), ), ); } }class ScrollViewDemo extends StatefulWidget { @override State createState() { // TODO: implement createState return ScrollViewDemoState(); } }class ScrollViewDemoState extends State { static const String routeName = '/material/tabs'; ScrollController _controller = new ScrollController(); ScrollController _controller2 = new ScrollController(); double h = 0; double d15; double d20; double d25; double d30; double d35; double d40; double d45; double d50; @override void initState() { // TODO: implement initState super.initState(); _controller.addListener(() { d15 = ScreenUtil().setWidth(15); d20 = ScreenUtil().setWidth(20); d25 = ScreenUtil().setWidth(25); d30 = ScreenUtil().setWidth(30); d35 = ScreenUtil().setWidth(35); d50 = ScreenUtil().setWidth(50); d40 = ScreenUtil().setWidth(40); d45 = ScreenUtil().setWidth(45); double d60 = ScreenUtil().setWidth(60); double d70 = ScreenUtil().setWidth(70); double d80 = ScreenUtil().setWidth(80); double d85 = ScreenUtil().setWidth(85); double d90 = ScreenUtil().setWidth(90); double d100 = ScreenUtil().setWidth(100); setState(() { if ((_controller.offset > d100)) { h = d50; } else if ((_controller.offset > d90)) { h = d45; } else if ((_controller.offset > d80)) { h = d40; } else if ((_controller.offset > d70)) { h = d35; } else if ((_controller.offset > d60)) { h = d30; } else if ((_controller.offset > d50)) { h = d25; } else if ((_controller.offset > d40)) { h = d20; } else if ((_controller.offset > d30)) { h = d15; } else { h = ScreenUtil().setWidth(0); } }); }); double start = 0; _controller2.addListener(() { //print("---->_controller2:${_controller2.offset}"); if ((_controller2.offset - start).abs() > 3) { _controller.jumpTo(_controller2.offset); start = _controller2.offset; } }); }@override Widget build(BuildContext context) {return new DefaultTabController( length: _allPages.length, child: new Scaffold( backgroundColor: Colors.white, body: new NestedScrollView( controller: _controller, headerSliverBuilder: (BuildContext context, bool innerBoxIsScrolled) { return [ new SliverOverlapAbsorber( handle: NestedScrollView.sliverOverlapAbsorberHandleFor(context), child: new SliverAppBar( actions: [ IconButton( icon: const Icon(Icons.share), tooltip: 'Add new entry', onPressed: () { /* ... */ }, ), ], leading: Container( child: Icon(Icons.backspace), width: 0, alignment: Alignment.center, ), title: Text("这是一个标题"), pinned: true, //固定在顶部 expandedHeight: ScreenUtil().setWidth(260), // 这个高度必须比flexibleSpace高度大 forceElevated: innerBoxIsScrolled, bottom: PreferredSize( child: new Container( decoration: BoxDecoration( borderRadius: BorderRadius.only( topLeft: Radius.circular(20), topRight: Radius.circular(20)), color: Colors.white, ), height: h, child: Row( mainAxisAlignment: MainAxisAlignment.spaceEvenly, children: [ Container( child: InkWell( child: Text( "导航一", style: TextStyle( color: h > 10 ? Colors.black : Colors.white), ), onTap: () { _controller2.animateTo( ScreenUtil().setWidth(260), duration: new Duration(seconds: 1), curve: Curves.ease); }, ), alignment: Alignment.center, ) , InkWell( child: Text("导航二", style: TextStyle( color: h > 10 ? Colors.black : Colors.white)), onTap: () { _controller2.animateTo( ScreenUtil().setWidth(600), duration: new Duration(seconds: 1), curve: Curves.ease); ; }) ], ),), preferredSize: new Size(double.infinity, h)), // 46.0为TabBar的高度,也就是tabs.dart中的_kTabHeight值,因为flutter不支持反射所以暂时没法通过代码获取 flexibleSpace: new Container( child: new Column( children: [ new Expanded( child: new Container( height: ScreenUtil().setWidth(170), decoration: BoxDecoration(color: Colors.white), child: Stack( fit: StackFit.expand, children: [ Image.asset( "images/test_1.png", fit: BoxFit.cover, height: ScreenUtil().setWidth(150), ), Stack( children: [ Container( height: ScreenUtil().setWidth(30), width: ScreenUtil().setWidth(375), decoration: BoxDecoration( borderRadius: BorderRadius.only( topLeft: Radius.circular(20), topRight: Radius.circular(20)), color: Colors.white, ), child: Container( margin: EdgeInsets.only( left: ScreenUtil().setWidth(125)), child: Row( children: [ Text( "这是测试的标题2", style: TextStyle( color: Colors.black, fontSize: ScreenUtil().setSp(15)), ), Text( "描述", style: TextStyle( color: Colors.red, fontSize: ScreenUtil().setSp(12)), ) ], ), ), ), Container( child: Container( margin: EdgeInsets.only( left: ScreenUtil().setWidth(10), right: ScreenUtil().setWidth(10)), child: Row( children: [ Image.asset( "images/test_2.png", fit: BoxFit.fill, width: ScreenUtil().setWidth(116), height: ScreenUtil().setWidth(164), ), Column( children: [ Text( "这是测试的标题1", style: TextStyle( color: Colors.white), ), Text( "副标题1", style: TextStyle( color: Colors.red), ), Text( "副标题2", style: TextStyle( color: Colors.red), ), Text( "副标题3", style: TextStyle( color: Colors.red), ), Text( "副标题4", style: TextStyle( color: Colors.red), ) ], ) ], )), height: h >= ScreenUtil().setWidth(20) ? (h >= ScreenUtil().setWidth(30) ? (h >= ScreenUtil().setWidth(35) ? (h >= ScreenUtil().setWidth(40) ? 0 : ScreenUtil().setWidth(80)) : ScreenUtil().setWidth(100)) : ScreenUtil().setWidth(140)) : ScreenUtil().setWidth(170), ), ], alignment: AlignmentDirectional.bottomEnd, ), ], ), width: double.infinity, ), ) ], ), ), ), ), ]; }, body: new TabBarView( children: _allPages.keys.map((_Page page) { return new SafeArea( top: false, bottom: false, child: new Builder( builder: (BuildContext context) { return new CustomScrollView( controller: _controller2, key: new PageStorageKey<_Page>(page), slivers: [ new SliverOverlapInjector( handle: NestedScrollView.sliverOverlapAbsorberHandleFor( context), ), new SliverPadding( padding: const EdgeInsets.symmetric( vertical: 8.0, horizontal: 16.0, ), sliver: new SliverFixedExtentList( itemExtent: _CardDataItem.height, delegate: new SliverChildBuilderDelegate( (BuildContext context, int index) { final _CardData data = _allPages[page][index]; return new Padding( padding: const EdgeInsets.symmetric( vertical: 8.0, ), child: new _CardDataItem( page: page, data: data, ), ); }, childCount: _allPages[page].length, ), ), ), ], ); }, ), ); }).toList(), ), //body: Column(children: [],), ), ), ); } }说明: NestedScrollView 与body 中的CustomScrollView滑动冲突解决,通过CustomScrollView的_controller2 控制NestedScrollView的_controller,以达到控制NestedScrollView的滚动的结果,当内部的CustomScrollView滚动时候_controller2监听器里 _controller.jumpTo(_controller2.offset),实现外层的NestedScrollView滚动

【flutter NestedScrollView 与其body中CustomScrollView滑动冲突解决】


    推荐阅读