实现嵌套 ListView (或者换句话说,可以包含在可滚动父级中的 ListView 小部件)的首选方法是什么?
设想一个“报告”页面,其中一个部分是一个逐条列表。
如果希望内部 ListView 可以独立于主滚动视图进行滚动,则应使用 NestedScrollView。否则,使用 CustomScrollView。
NestedScrollView
CustomScrollView
下面是一些说明 NestedScrollView方法的代码。
import 'package:flutter/material.dart'; void main() { runApp(new MyApp()); } class MyApp extends StatelessWidget { @override Widget build(BuildContext context) { return new MaterialApp( title: 'Flutter Demo', theme: new ThemeData( primarySwatch: Colors.blue, ), home: new MyHomePage(), ); } } class MyHomePage extends StatelessWidget { @override Widget build(BuildContext context) { return new Scaffold( body: new NestedScrollView( headerSliverBuilder: (BuildContext context, bool innerBoxIsScrolled) { return <Widget>[ new SliverAppBar( pinned: true, title: new Text('Flutter Demo'), ), ]; }, body: new Column( children: <Widget>[ new FlutterLogo(size: 100.0, colors: Colors.purple), new Container( height: 300.0, child: new ListView.builder( itemCount: 60, itemBuilder: (BuildContext context, int index) { return new Text('Item $index'); }, ), ), new FlutterLogo(size: 100.0, colors: Colors.orange), ], ), ), ); } }
对于子 ListView,使用该参数:
shrinkWrap: true, physics: ClampingScrollPhysics(),
截图:
密码:
var _container = Container( height: 200, color: Colors.blue, margin: EdgeInsets.symmetric(vertical: 10), ); @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar(title: Text("ListView")), body: Padding( padding: const EdgeInsets.all(40.0), child: ListView( // parent ListView children: <Widget>[ _container, _container, Container( height: 200, // give it a fixed height constraint color: Colors.teal, // child ListView child: ListView.builder(itemBuilder: (_, i) => ListTile(title: Text("Item ${i}"))), ), _container, _container, _container, ], ), ), ); }
增加 physics: ClampingScrollPhysics()和 shrinkWrap: true对我来说是个好办法。
physics: ClampingScrollPhysics()
shrinkWrap: true
示例代码:
@override Widget build(BuildContext context) { return Container( child: Column( mainAxisSize: MainAxisSize.min, children: <Widget>[ Expanded( child: ListView.builder( shrinkWrap: true, itemCount: 123, itemBuilder: (BuildContext context, int index) { return Column( crossAxisAlignment: CrossAxisAlignment.start, children: <Widget>[ Text('Parent'), ListView.builder( itemCount: 2, physics: ClampingScrollPhysics(), shrinkWrap: true, itemBuilder: (BuildContext context, int index) { return Text('Child'); }), ], ); }), ) ], ), ); }
感谢 Serdar Polat:
ListView.builder( // outer ListView itemCount: 4, itemBuilder: (_, index) { return Column( children: [ Container( color: Colors.blue, alignment: Alignment.center, child: Text('Header $index'), ), ListView.builder( // inner ListView shrinkWrap: true, // 1st add physics: ClampingScrollPhysics(), // 2nd add itemCount: 10, itemBuilder: (_, index) => ListTile(title: Text('Item $index')), ) ], ); }, )
对于内部列表视图,我刚刚添加了下面的代码,它为我解决了
shrinkWrap: true, physics: ScrollPhysics(),
我用这个:
scrollController.addListener(onScroll); void onScroll(){ if(scrollController.offset == 0.0 || scrollController.position.extentBefore == 0.0 || scrollController.position.extentAfter == 0.0){ scrollPhysics = NeverScrollableScrollPhysics(); Future.delayed(Duration(seconds: 1), (){ scrollPhysics = ClampingScrollPhysics(); setState((){}); }); setState((){});; } }
Expanded( child: ListView.builder( shrinkWrap: true, padding: const EdgeInsets.all(8), itemCount: requestList.length, itemBuilder: (BuildContext context, int index) { int que = index; return Column( crossAxisAlignment: CrossAxisAlignment.start, children: <Widget>[ Container( padding: const EdgeInsets.only( left: 20, top: 10, bottom: 10, right: 20), child: Text( '${que++} . ${requestList[index].question}', textAlign: TextAlign.center, style: TextStyle( fontSize: 14, color: HexColor(HexColor.black), fontFamily: 'montserrat_regular', decoration: TextDecoration.none, ), )), ListView.builder( itemCount: requestList[index].questionOptions!.length, physics: ClampingScrollPhysics(), shrinkWrap: true, itemBuilder: (BuildContext context, int subindex) { return Row( children: <Widget>[ Radio( value: 1, groupValue: radio_value[index], onChanged: (values) async { setState(() { radio_value[index] = 1; qutionCheckModel[index].response = "yes"; }); }), Container( child: Text( requestList[index].questionOptions![subindex], textAlign: TextAlign.center, style: TextStyle( fontSize: 14, color: HexColor(HexColor.black), fontFamily: 'montserrat_regular', decoration: TextDecoration.none, ), ), ), ], ); }), ], ); }), ),
ShrinkWrap 包装内容,ClampingScrollPhysical 使用父滚动条
ListView.builder( shrinkWrap: true, physics: const ClampingScrollPhysics(), itemCount: yourList.length, itemBuilder: (context, index) => YourWidget(items[index]), ),