如何在ListView中使用多个ListView.builder并使用Flutter进行嵌套滚动



我在使用ListView和ListView.builder的组合实现屏幕时遇到了一个问题。示例代码如下-

Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text('AppBar'),
),
body: Container(
height: MediaQuery.of(context).size.height,
child: ListView(
controller: _mainScrollController,
children: <Widget>[
ListView.builder(....) // ListView.builder #1
ListView.builder(....) // ListView.builder #2
ListView.builder(....) // ListView.builder #3

]
)
)

它需要单独滚动内部列表视图,当用户移动到任何列表视图的底部或顶部时,相关内部列表的滚动将停止,控件将移动主窗口小部件。

有什么方法可以实现它并在一个小部件中使用多个ScrollContoller吗?

尝试将CustomScrollView与多个SliverList:一起使用

/// Flutter code sample for CustomScrollView
// By default, if items are inserted at the "top" of a scrolling container like
// [ListView] or [CustomScrollView], the top item and all of the items below it
// are scrolled downwards. In some applications, it's preferable to have the
// top of the list just grow upwards, without changing the scroll position.
// This example demonstrates how to do that with a [CustomScrollView] with
// two [SliverList] children, and the [CustomScrollView.center] set to the key
// of the bottom SliverList. The top one SliverList will grow upwards, and the
// bottom SliverList will grow downwards.
import 'package:flutter/material.dart';
void main() => runApp(const MyApp());
/// This is the main application widget.
class MyApp extends StatelessWidget {
const MyApp({Key? key}) : super(key: key);
static const String _title = 'Flutter Code Sample';
@override
Widget build(BuildContext context) {
return const MaterialApp(
title: _title,
home: MyStatefulWidget(),
);
}
}
/// This is the stateful widget that the main application instantiates.
class MyStatefulWidget extends StatefulWidget {
const MyStatefulWidget({Key? key}) : super(key: key);
@override
State<MyStatefulWidget> createState() => _MyStatefulWidgetState();
}
/// This is the private State class that goes with MyStatefulWidget.
class _MyStatefulWidgetState extends State<MyStatefulWidget> {
List<int> top = <int>[];
List<int> bottom = <int>[0];
@override
Widget build(BuildContext context) {
const Key centerKey = ValueKey<String>('bottom-sliver-list');
return Scaffold(
appBar: AppBar(
title: const Text('Press on the plus to add items above and below'),
leading: IconButton(
icon: const Icon(Icons.add),
onPressed: () {
setState(() {
top.add(-top.length - 1);
bottom.add(bottom.length);
});
},
),
),
body: CustomScrollView(
center: centerKey,
slivers: <Widget>[
SliverList(
delegate: SliverChildBuilderDelegate(
(BuildContext context, int index) {
return Container(
alignment: Alignment.center,
color: Colors.blue[200 + top[index] % 4 * 100],
height: 100 + top[index] % 4 * 20.0,
child: Text('Item: ${top[index]}'),
);
},
childCount: top.length,
),
),
SliverList(
key: centerKey,
delegate: SliverChildBuilderDelegate(
(BuildContext context, int index) {
return Container(
alignment: Alignment.center,
color: Colors.blue[200 + bottom[index] % 4 * 100],
height: 100 + bottom[index] % 4 * 20.0,
child: Text('Item: ${bottom[index]}'),
);
},
childCount: bottom.length,
),
),
],
),
);
}
}

ListViewshrinkWrapSliverList

查看此以获取更多信息,以及此。

ShrinkWrApp

// Copyright (c) 2019, the Dart project authors.  Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
import 'package:flutter/material.dart';
import 'dart:math' as math;
void main() {
runApp(ShrinkWrApp());
}
class ShrinkWrApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
debugShowCheckedModeBanner: false,
title: 'ShrinkWrap vs Slivers',
home: Scaffold(
appBar: AppBar(
title: const Text("ShrinkWrap, Street Rat, I don't, Buy that!"),
),
body: const ShrinkWrapSlivers(),
),
);
}
}
class ShrinkWrapSlivers extends StatefulWidget {
const ShrinkWrapSlivers({
Key? key,
}) : super(key: key);
@override
_ShrinkWrapSliversState createState() => _ShrinkWrapSliversState();
}
class _ShrinkWrapSliversState extends State<ShrinkWrapSlivers> {
List<ListView> innerLists = [];
final numLists = 15;
final numberOfItemsPerList = 100;
@override
void initState() {
super.initState();
for (int i = 0; i < numLists; i++) {
final _innerList = <ColorRow>[];
for (int j = 0; j < numberOfItemsPerList; j++) {
_innerList.add(const ColorRow());
}
innerLists.add(
ListView.builder(
itemCount: numberOfItemsPerList,
itemBuilder: (BuildContext context, int index) => _innerList[index],
shrinkWrap: true,
physics: const NeverScrollableScrollPhysics(),
),
);
}
}
@override
Widget build(BuildContext context) {
return ListView.builder(
itemCount: numLists,
itemBuilder: (context, index) => innerLists[index]);
}
}
@immutable
class ColorRow extends StatefulWidget {
const ColorRow({Key? key}) : super(key: key);
@override
State createState() => ColorRowState();
}
class ColorRowState extends State<ColorRow> {
Color? color;
@override
void initState() {
super.initState();
color = randomColor();
}
@override
Widget build(BuildContext context) {
print('Building ColorRowState');
return Container(
decoration: BoxDecoration(
gradient: LinearGradient(
begin: Alignment.topLeft,
end: Alignment.bottomRight,
colors: [
randomColor(),
randomColor(),
],
),
),
child: Row(
children: <Widget>[
Padding(
padding: const EdgeInsets.all(8.0),
child: Container(height: 50, width: 50, color: Colors.white),
),
Flexible(
child: Column(
children: const <Widget>[
Padding(
padding: EdgeInsets.all(8),
child: Text('I'm a widget!',
style: TextStyle(color: Colors.white)),
),
],
),
),
],
),
);
}
}
Color randomColor() =>
Color((math.Random().nextDouble() * 0xFFFFFF).toInt()).withOpacity(1.0);

SliversApp

// Copyright (c) 2019, the Dart project authors.  Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
import 'package:flutter/material.dart';
import 'dart:math' as math;
void main() {
runApp(SliversApp());
}
class SliversApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
debugShowCheckedModeBanner: false,
title: 'ShrinkWrap vs Slivers',
home: Scaffold(
appBar: AppBar(
title: const Text("Revenge of the Slivers"),
),
body: const ShrinkWrapSlivers(),
),
);
}
}
class ShrinkWrapSlivers extends StatefulWidget {
const ShrinkWrapSlivers({
Key? key,
}) : super(key: key);
@override
_ShrinkWrapSliversState createState() => _ShrinkWrapSliversState();
}
class _ShrinkWrapSliversState extends State<ShrinkWrapSlivers> {
List<SliverList> innerLists = [];
final numLists = 15;
final numberOfItemsPerList = 100;
@override
void initState() {
super.initState();
for (int i = 0; i < numLists; i++) {
final _innerList = <ColorRow>[];
for (int j = 0; j < numberOfItemsPerList; j++) {
_innerList.add(const ColorRow());
}
innerLists.add(
SliverList(
delegate: SliverChildBuilderDelegate(
(BuildContext context, int index) => _innerList[index],
childCount: numberOfItemsPerList,
),
),
);
}
}
@override
Widget build(BuildContext context) {
return CustomScrollView(slivers: innerLists);
}
}
@immutable
class ColorRow extends StatefulWidget {
const ColorRow({Key? key}) : super(key: key);
@override
State createState() => ColorRowState();
}
class ColorRowState extends State<ColorRow> {
Color? color;
@override
void initState() {
super.initState();
color = randomColor();
}
@override
Widget build(BuildContext context) {
print('Building ColorRowState');
return Container(
decoration: BoxDecoration(
gradient: LinearGradient(
begin: Alignment.topLeft,
end: Alignment.bottomRight,
colors: [
randomColor(),
randomColor(),
],
),
),
child: Row(
children: <Widget>[
Padding(
padding: const EdgeInsets.all(8.0),
child: Container(height: 50, width: 50, color: Colors.white),
),
Flexible(
child: Column(
children: const <Widget>[
Padding(
padding: EdgeInsets.all(8),
child: Text('I'm a widget!',
style: TextStyle(color: Colors.white)),
),
],
),
),
],
),
);
}
}
Color randomColor() =>
Color((math.Random().nextDouble() * 0xFFFFFF).toInt()).withOpacity(1.0);

最新更新