Flutter有没有办法把一个很长的ListView拆分成多个"pages"?
Is there a way in Flutter to split a long ListView into multiple "pages"?
我是编码初学者,我正在尝试创建一个应用程序来练习和学习 dart 和 flutter。
我的应用程序有一个包含长 ListView(700 个项目)的页面,我想制作某种“页面导航器”以将 ListView 分成 7 个(每页 100 个项目)。
我知道分页 ListView,但我不知道 link 结果。
很抱歉我在解释我想做的事情时词汇量很差,这是一个例子
Example of "pages navigator"
最终,我希望这个“拆分的 ListView”中的所有项目都可以通过搜索栏进行过滤。
这是我目前的 list.dart 代码:
class SongList extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Container(
child: _buildListView(context),
);
}
ListView _buildListView(BuildContext context) {
return ListView.separated(
physics: NeverScrollableScrollPhysics(),
shrinkWrap: true,
itemCount: 700,
itemBuilder: (_, index) {
final count = index + 1;
return new ListTile(
leading: new CircleAvatar(
child: new Text(
"$count",
style: TextStyle(color: kBackgroundColor),
),
backgroundColor: kPrimaryColor,
),
title: new Text("Song #$count"),
trailing: Icon(Icons.navigate_next),
onTap: () {
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => SongDetail(index),
),
);
},
);
},
separatorBuilder: (context, index) {
return Divider();
},
);
}
}
更新:我做到了!
我发现这个包太棒了!
https://pub.dev/packages/number_paginator
所以我从下面更新了代码,并将 CupertinoSlidingSegmentedControl 替换为 NumberPaginator 小部件。
这里是代码:
child: NumberPaginator(
numberPages: 7,
onPageChange: (int index) {
setState(() {
currentPage = index;
});
},
),
这些包甚至提供了一些属性来自定义页面指示器的颜色和形状。
旧解
我希望这对某人有所帮助。请注意,我仍然是一名学习者,如果此代码中的某些内容已关闭,可能会更好地发表评论并添加您的贡献。
我在 Flutter 中没有找到任何原生的“分页小部件”,所以我最终使用 CupertinoSlidingSegmentedControl 作为“分页小部件”和 CupertinoUserInterfaceLevel 用于 segments/pages.
的“正文”
我的歌曲列表由数据库助手和一些查询提供,我致力于将我的 700 个项目列表拆分为 7 个查询并根据选定的 segment/page 指标调用它们。
这是我的代码,其中包含一些有用的注释。
import 'package:flutter/material.dart';
import 'package:flutter/cupertino.dart'; // Required in order to use Cupertino Widgets
import '/assets/data/queries.dart'; // My queries are in another dart file
import '/assets/data/db_tables.dart';
import 'songs_detail.dart';
class SongsBody extends StatefulWidget {
@override
_SongsBodyState createState() => _SongsBodyState();
}
class _SongsBodyState extends State<SongsBody> {
// Change this in order to edit the segment/paging widget, you can put text and icons
final Map<int, Widget> children = const <int, Widget>{
0: Text('1'),
1: Text('2'),
2: Text('3'),
3: Text('4'),
4: Text('5'),
5: Text('6'),
6: Text('7'),
};
// Change this to set the initial segment/page
int currentSegment = 0;
// This is required to update the state when you tap on another segment/page
void onValueChanged(newValue) {
setState(() {
currentSegment = newValue;
});
}
// My queries from queries.dart are called here and used later in the code
final List<Future<List?>> _query = [
QueryCtr().getSongsFrom1To100(),
QueryCtr().getSongsFrom101To200(),
QueryCtr().getSongsFrom201To300(),
QueryCtr().getSongsFrom301To400(),
QueryCtr().getSongsFrom401To500(),
QueryCtr().getSongsFrom501To600(),
QueryCtr().getSongsFrom601To700(),
];
@override
Widget build(BuildContext context) {
return Column(
children: <Widget>[
// This is the segment control widget (our "paging" widget)
CupertinoSlidingSegmentedControl<int>(
children: children,
onValueChanged: onValueChanged,
groupValue: currentSegment,
),
const Divider(),
// This is the "body" of our segment/page
CupertinoUserInterfaceLevel(
data: CupertinoUserInterfaceLevelData.base,
// My listview is now called with a future builder because I'm getting the data from my database
child: Builder(
builder: (BuildContext context) {
return FutureBuilder<List?>(
// This is the interesting part: I update only the query according to the selected segment
future: _query[currentSegment],
initialData: const [],
builder: (context, snapshot) {
return snapshot.hasData
// If there is some data show them in a listview wrapped in expanded
? Expanded(
child: ListView.separated(
physics: const ScrollPhysics(),
shrinkWrap: true,
itemCount: snapshot.data!.length,
itemBuilder: (context, i) {
// Here I decided to code a separate widget to build the rows of my listview
return _buildRow(snapshot.data![i]);
},
separatorBuilder: (context, index) {
return const Divider();
},
),
)
// If there is no data return a progress indicator
: const Center(
child: CircularProgressIndicator(),
);
},
);
},
),
),
],
);
}
Widget _buildRow(Raccolta get) {
return ListTile(
leading: CircleAvatar(
child: Text(
get.songId.toString(),
),
),
title: Text(get.songTitle),
trailing: const Icon(
Icons.navigate_next,
color: somecolor,
),
onTap: () {
FocusScope.of(context).unfocus();
int songId = get.songId;
String songTitle = get.songTitle;
String songText = get.songText;
Navigator.push(
context,
MaterialPageRoute(
builder: (context) {
return SongsDetail(songId, songTitle, songText);
},
),
);
},
);
}
}
我是编码初学者,我正在尝试创建一个应用程序来练习和学习 dart 和 flutter。
我的应用程序有一个包含长 ListView(700 个项目)的页面,我想制作某种“页面导航器”以将 ListView 分成 7 个(每页 100 个项目)。 我知道分页 ListView,但我不知道 link 结果。 很抱歉我在解释我想做的事情时词汇量很差,这是一个例子
Example of "pages navigator"
最终,我希望这个“拆分的 ListView”中的所有项目都可以通过搜索栏进行过滤。
这是我目前的 list.dart 代码:
class SongList extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Container(
child: _buildListView(context),
);
}
ListView _buildListView(BuildContext context) {
return ListView.separated(
physics: NeverScrollableScrollPhysics(),
shrinkWrap: true,
itemCount: 700,
itemBuilder: (_, index) {
final count = index + 1;
return new ListTile(
leading: new CircleAvatar(
child: new Text(
"$count",
style: TextStyle(color: kBackgroundColor),
),
backgroundColor: kPrimaryColor,
),
title: new Text("Song #$count"),
trailing: Icon(Icons.navigate_next),
onTap: () {
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => SongDetail(index),
),
);
},
);
},
separatorBuilder: (context, index) {
return Divider();
},
);
}
}
更新:我做到了!
我发现这个包太棒了! https://pub.dev/packages/number_paginator
所以我从下面更新了代码,并将 CupertinoSlidingSegmentedControl 替换为 NumberPaginator 小部件。
这里是代码:
child: NumberPaginator(
numberPages: 7,
onPageChange: (int index) {
setState(() {
currentPage = index;
});
},
),
这些包甚至提供了一些属性来自定义页面指示器的颜色和形状。
旧解
我希望这对某人有所帮助。请注意,我仍然是一名学习者,如果此代码中的某些内容已关闭,可能会更好地发表评论并添加您的贡献。
我在 Flutter 中没有找到任何原生的“分页小部件”,所以我最终使用 CupertinoSlidingSegmentedControl 作为“分页小部件”和 CupertinoUserInterfaceLevel 用于 segments/pages.
的“正文”我的歌曲列表由数据库助手和一些查询提供,我致力于将我的 700 个项目列表拆分为 7 个查询并根据选定的 segment/page 指标调用它们。
这是我的代码,其中包含一些有用的注释。
import 'package:flutter/material.dart';
import 'package:flutter/cupertino.dart'; // Required in order to use Cupertino Widgets
import '/assets/data/queries.dart'; // My queries are in another dart file
import '/assets/data/db_tables.dart';
import 'songs_detail.dart';
class SongsBody extends StatefulWidget {
@override
_SongsBodyState createState() => _SongsBodyState();
}
class _SongsBodyState extends State<SongsBody> {
// Change this in order to edit the segment/paging widget, you can put text and icons
final Map<int, Widget> children = const <int, Widget>{
0: Text('1'),
1: Text('2'),
2: Text('3'),
3: Text('4'),
4: Text('5'),
5: Text('6'),
6: Text('7'),
};
// Change this to set the initial segment/page
int currentSegment = 0;
// This is required to update the state when you tap on another segment/page
void onValueChanged(newValue) {
setState(() {
currentSegment = newValue;
});
}
// My queries from queries.dart are called here and used later in the code
final List<Future<List?>> _query = [
QueryCtr().getSongsFrom1To100(),
QueryCtr().getSongsFrom101To200(),
QueryCtr().getSongsFrom201To300(),
QueryCtr().getSongsFrom301To400(),
QueryCtr().getSongsFrom401To500(),
QueryCtr().getSongsFrom501To600(),
QueryCtr().getSongsFrom601To700(),
];
@override
Widget build(BuildContext context) {
return Column(
children: <Widget>[
// This is the segment control widget (our "paging" widget)
CupertinoSlidingSegmentedControl<int>(
children: children,
onValueChanged: onValueChanged,
groupValue: currentSegment,
),
const Divider(),
// This is the "body" of our segment/page
CupertinoUserInterfaceLevel(
data: CupertinoUserInterfaceLevelData.base,
// My listview is now called with a future builder because I'm getting the data from my database
child: Builder(
builder: (BuildContext context) {
return FutureBuilder<List?>(
// This is the interesting part: I update only the query according to the selected segment
future: _query[currentSegment],
initialData: const [],
builder: (context, snapshot) {
return snapshot.hasData
// If there is some data show them in a listview wrapped in expanded
? Expanded(
child: ListView.separated(
physics: const ScrollPhysics(),
shrinkWrap: true,
itemCount: snapshot.data!.length,
itemBuilder: (context, i) {
// Here I decided to code a separate widget to build the rows of my listview
return _buildRow(snapshot.data![i]);
},
separatorBuilder: (context, index) {
return const Divider();
},
),
)
// If there is no data return a progress indicator
: const Center(
child: CircularProgressIndicator(),
);
},
);
},
),
),
],
);
}
Widget _buildRow(Raccolta get) {
return ListTile(
leading: CircleAvatar(
child: Text(
get.songId.toString(),
),
),
title: Text(get.songTitle),
trailing: const Icon(
Icons.navigate_next,
color: somecolor,
),
onTap: () {
FocusScope.of(context).unfocus();
int songId = get.songId;
String songTitle = get.songTitle;
String songText = get.songText;
Navigator.push(
context,
MaterialPageRoute(
builder: (context) {
return SongsDetail(songId, songTitle, songText);
},
),
);
},
);
}
}