Flutter入门——面向Android开发者——列表视图和适配器
一、Flutter中ListView的替代品是什么?
相当于Flutter中的ListView。
在Android ListView中,您创建一个适配器并将其传递到LisstView,ListView会使用适配器返回的内容呈现每一行。但是,您必须确保回收行,否则,您会遇到各种更狂的视觉故障和内存问题。
由于Flutter的不可变小部件模式,您将小部件列表传递给ListView,Flutter负责确保滚动快速流畅。
void main() {
runApp(const SampleApp());
}
class SampleApp extends StatelessWidget {
const SampleApp({Key? key}) : super(key: key);
// This widget is the root off your application
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Smple App',
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: const SampleAppPage(),
);
}
}
class SampleAppPage extends StatefulWidget {
const SampleAppPage({Key? key}) : super(key: key);
@override
State<SampleAppPage> createState() => _SampleAppPageState();
}
class _SampleAppPageState extends State<SampleAppPage> {
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text('Sample App'),
),
body: ListView(children: _getListData()),
);
}
List<Widget> _getListData() {
List<Widget> widgets = [];
for (int i = 0; i < 100; i++) {
widgets.add(Padding(
padding: const EdgeInsets.all(10.0),
child: Text('Row $i'),
));
}
return widgets;
}
}
二、我如何知道点击了哪个列表项?
在Android中,ListView有一个方法来找出单击了哪个项目,onItemClickListener
。在Flutter中,使用传入的小哦部件提供的触摸处理。
import 'dart:developer' as developer;
import 'package:flutter/materil.dart';
void main() {
runApp(const SampleApp());
}
class SampleApp extends StatelessWidget {
const SampleApp({Key? key}) : super(key: key);
// Thhis widget is the root of your application
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Sample App',
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: const SampleAppPage(),
);
}
}
class SampleAppPage extends StatefulWidget {
const SampleAppPage({Key? key}) : super(key: key);
@override
State<SampleAppPage> createState => _SampleAppPageState();
}
class _SampleAppPageState extends State<SampleAppPage> {
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text('Sample App'),
),
body: ListView(children: _getListData()),
);
}
List<Widget> _getListData() {
List<Widget> widgets = [];
for (int i = 0; i < 100; i ++) {
widget.add(
GestureDetector(
onTap() {
developer.log('row tapped');
},
child: Padding(
padding: EdgeInsets.all(10.0),
child: Text('Row $i'),
),
),
);
}
}
}
三、如何动态更新ListView?
在Android上,您更新适配器并调用notifyDataSetChanged
.
在Flutter中,如果您要更新小部件列表通过setState()
,您很快就会发现您的数据在视觉上没有变化。这是因为当setState()
调用时,Flutter渲染引擎会查看小部件树以查看是否有任何更改。当它获取你的ListView
,通过执行==
检查,并确定这两个ListView
是相同的。什么都没有改变,所以不需要更新。
对于更新您的简单方法,在ListView
中创建一个新List
的setState()
,并将数据从旧列表复制到新列表。虽然这种方法很简单,但不建议用于大型数据集,如下一个示例所示。
import 'dart:developer' as developer;
import 'package:flutter/material.dart';
void main() {
runApp(const SampleApp());
}
class SampleApp extends StatelessWidget {
const SampleApp({Key? key}) : super(key: key);
//This widget is the root of your application
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Sample App',
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: const SampleAppPade(),
);
}
}
class SampleAppPage extends StatefulWidget {
const SampleAppPage({Key? key}) : super(key: key);
@override
State<SampleAppPage> createState() => _SampleAppPageState();
}
class _SampleAppPageState extends State<SampleAppPage> {
List<Widget> widgets = [];
@override
void initState() {
super.initState();
for (int i = 0; i < 100; i++) {
widgets.add(getRow(i));
}
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text('Sample App'),
),
body: ListView(children: widgets),
);
}
Widget getRow(int i) {
return GestureDetector(
onTap: () {
setState(() {
widgets = List.form(widgets);
widgets.add(getRow(widgets.length));
develop.log('row $i');
});
},
child: Padding(
padding: const EdgeInsets.all(10.0),
child: Text('Row $i')
),
);
}
}
构建列表的推荐、高效且有效的方法是使用ListView.Builder
。当您拥有动态数据List
或List
包含大量数据时,此方法非常有用。这本质上相当于Android的RecyclerView,它会自动为你回收列表元素。
import 'dart:developer' as developer;
import 'package:flutter/material.dart';
void main() {
runApp(const SampleApp());
}
class SampleApp extends StatelessWidget {
const SampleApp({Key? key}) : super(key: key);
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Sample App',
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: const SampleAppPage(),
);
}
}
class SampleAppPage extends StatefulWidget {
const SampleAppPage({Key? key}) : super(key: key);
@override
State<SampleAppPage> createState => _SampleAppPageState();
}
class _SampleAppPageState extends State<SampleAppPage> {
List<Widget> widgets = [];
@override
void initState() {
super.initState();
for (int i = 0; i < 100; i ++) {
widgets.add(getRow(i));
}
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text('Sample App'),
),
body: ListView.builder(
itemCount: widgets.length,
itemBuilder: (context, position) {
return getRow(position);
}
),
);
}
Widget getRow(int i) {
return GestureDetector(
onTap: () {
setState(() {
widgets.add(getRow(widgets.length));
developer.log('row $i');
});
},
child: Padding(
padding: const EdgeInsets.all(10.0),
child: Text('Row $i'),
),
);
}
}
与其创建ListView
,不如创建一个带有ListView.builder
两个关键参数的视图:列表的初始长度和一个ItemBuilder
函数。
ItemBuilder
功能类似于Android适配器中的功能getView
;它需要一个位置,并返回您想要在该位置呈现的行。
最后,但也是最重要的是,请注意该onTap()
函数不再重新创建列表,而是add
上去。
转载自:https://juejin.cn/post/7183223381158789175