likes
comments
collection
share

Flutter入门——面向Android开发者——列表视图和适配器

作者站长头像
站长
· 阅读数 45

一、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中创建一个新ListsetState(),并将数据从旧列表复制到新列表。虽然这种方法很简单,但不建议用于大型数据集,如下一个示例所示。

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。当您拥有动态数据ListList包含大量数据时,此方法非常有用。这本质上相当于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
评论
请登录