65.9K
CodeProject 正在变化。 阅读更多。
Home

Flutter 入门:教程 4 ListView

starIconstarIconstarIconstarIconstarIcon

5.00/5 (2投票s)

2018年7月18日

CPOL

5分钟阅读

viewsIcon

40409

downloadIcon

744

Flutter ListView:满足日常需求的滚动控件。

引言

欢迎来到 Flutter 入门系列教程的另一篇文章。在这里,我将探讨 ListView 小部件。根据 Flutter 官网的说法:

引用

ListView 是最常用的滚动小部件。它在其滚动方向上一个接一个地显示其子项。

让我们更深入地了解 Flutter,这个有前景的未来框架。

背景

本文的最终目标是创建这样的 UI:

在这里,我们希望创建一个可滚动的列表,该列表显示城市受欢迎的地标作为其展示图片,附加信息包括城市人口以及它所在的国家。

教程目标

在本文中,我们将创建一个基于 ListView 的应用程序。首先,我们将展示一个非常基础的城市列表;然后,我们将在此基础上构建,以显示城市的 名称人口、所属的 国家。第三,我们将展示其受欢迎的地标作为图片;最后,我们将进一步增强 UI 并显示用户点击 ListItem 时的 SnackBar(一种小型消息通知)。

Using the Code

任务 #1:让我们从应用程序的第一个阶段开始,在该阶段中,我们将创建显示仅城市名称的基础 ListView

首先,在 model 文件夹下创建一个名为 City 的类(你需要在 lib 文件夹内创建该文件夹),它将作为显示的基础模型。如果你不知道如何创建 Flutter 项目,我在这篇文章中已详细解释,请参考以获取一般知识。

class City {

  //--- Name Of City
  final String name;
  //-- image
  final String image;
  //--- population
  final String population;
   //--- country
  final String country;

  City({this.name,this.country,this.population,this.image}); 
}

在这个类中,我提供了一个基础的骨架类,它将为图块提供显示模型。为了简单起见,我在这里也添加了代码到 City 类以提供城市列表,尽管这不是一种好的做法。

static List<City> allCities()
{
  var lstOfCities = new List<City>();

  lstOfCities.add(new City(name:"Delhi",country: "India",population: "19 mill",image: "delhi.png"));
  lstOfCities.add(new City(name:"London",
                  country: "Britain",population: "8 mill",image: "london.png"));
  lstOfCities.add(new City(name:"Vancouver",
                  country: "Canada",population: "2.4 mill",image: "vancouver.png"));
  lstOfCities.add(new City(name:"New York",
                  country: "USA",population: "8.1 mill",image: "newyork.png"));
  lstOfCities.add(new City(name:"Paris",
                  country: "France",population: "2.2 mill",image: "paris.png"));
  lstOfCities.add(new City(name:"Berlin",
                  country: "Germany",population: "3.7 mill",image: "berlin.png"));
  return lstOfCities;
}

至此,我们的 City 类就完成了,将所有代码保存在 city.dart 文件中。现在,在 lib 文件夹内添加另一个名为 pages 的文件夹,然后添加我们唯一的页面 homepage.dart。由于我们不需要在这里处理状态,因此我们可以简单地构建一个继承自 StatelessWidgetHomePage 类。这是初始代码:

import 'package:flutter/material.dart';
import 'package:flutter4_listview/model/city.dart';

class HomePage extends StatelessWidget {
 
final List<City> _allCities = City.allCities();

HomePage() {}

@override
Widget build(BuildContext context) {
  return new Scaffold(
      appBar: new AppBar(
        title: new Text(
          "Cites around world",
          style: new TextStyle(
              fontSize: 18.0,
              fontWeight: FontWeight.bold,
              color: Colors.black87),
        ),
      ),
      body: new Padding(
          padding: EdgeInsets.fromLTRB(0.0, 10.0, 0.0, 0.0),
          child: getHomePageBody(context)));
}

getHomePageBody(BuildContext context) {
  return ListView.builder(
    itemCount: _allCities.length,
    itemBuilder: _getItemUI,
    padding: EdgeInsets.all(0.0),
  );
}
  // First Attempt
  Widget _getItemUI(BuildContext context, int index) {
    return new Text(_allCities[index].name);
  }
}

在上面的代码中,我们做了以下事情:

  • 我包含了类变量 _allCities,它将包含所有城市数据。虽然上述提供数据给变量的方法不对,但使用 依赖注入 会是更好的方式。
  • 我创建了一个简单的 material app scaffold,它提供了应用程序的基本骨架,通过提供基本的 AppBar 和用于放置小部件的 body。
  • 我使用 ListView.builder 方法创建了 scaffold 的 body,因为它为创建无限列表提供了更好的基础架构,它仅动态回调那些在屏幕上可见的索引,从而提高了性能
  • 我使用普通的文本小部件构建了每个图块,目前仅显示城市名称。在本教程中,我们将进一步扩展它。

最后但同样重要的是,对于任务 #1,请删除 main.dart 文件中的所有内容,并粘贴以下代码,将 HomePage 类设置为应用程序的启动页。此文件将不再进行任何更改。

import 'package:flutter/material.dart';
import 'package:flutter4_listview/pages/homepage.dart';

void main() => runApp(new MyApp());

class MyApp extends StatelessWidget {
  // This widget is the root of your application.
  @override
  Widget build(BuildContext context) {
    return new MaterialApp(
      title: 'Flutter Demo',
      theme: new ThemeData(
        primarySwatch: Colors.amber,
      ),
      home: new HomePage(),
    );
  }
}

现在在模拟器中运行应用程序并查看结果。

至此,我完成了任务 #1。

任务 #2:在此任务中,我想显示所有内容,即 City 类对象公开的所有属性。

如上代码所示,显示文本属性相对容易。你可以使用 Text 小部件并放置任何你想要的文本,只需将其放入构造函数中即可。但是,显示图片需要对 pubspec.yaml(主配置文件)进行一些配置。在这个演示中,我从 Google 图片搜索中收集了不同城市的著名地标。我将它们保存在根位置的 assets 文件夹中。添加图片后,我的文件夹结构如下:

现在,由于所有这些图片都已静态包含在项目中,我们需要在 pubspec.yaml 中像这样包含它们:

assets:
  - assets/berlin.png
  - assets/delhi.png
  - assets/london.png
  - assets/newyork.png
  - assets/paris.png
  - assets/vancouver.png

请记住,上述代码应放在 flutter 部分下,并且要小心空格,否则图片可能无法加载或出现编译错误。最安全的做法是为 assets: 使用一个制表符,为以 dash (-) 开头的图片使用两个制表符。

要加载图片到页面,我们必须使用 Image.asset 工厂构造函数,并提供图片的相对路径。所以基本上,我们将使用 Card 小部件来显示图片以及其他公开的属性。现在,修改后的 _getItemUi() 代码如下:

Widget _getItemUI(BuildContext context, int index) {
  return new Card(
      child: new Column(
    
    children: <Widget>[
      new ListTile(
        leading: new Image.asset(
          "assets/" + _allCities[index].image,
          fit: BoxFit.cover,
          width: 100.0,
        ),

        title: new Text(
          _allCities[index].name,
          style: new TextStyle(fontSize: 14.0, fontWeight: FontWeight.bold),
        ),
        subtitle: new Column(
            mainAxisAlignment: MainAxisAlignment.start,
            crossAxisAlignment: CrossAxisAlignment.start,
            children: <Widget>[
              new Text(_allCities[index].country,
                  style: new TextStyle(
                      fontSize: 13.0, fontWeight: FontWeight.normal)),
              new Text('Population: ${_allCities[index].population}',
                  style: new TextStyle(
                      fontSize: 11.0, fontWeight: FontWeight.normal)),
            ]),
        //trailing: ,
        onTap: () {
          _showSnackBar(context, _allCities[index]);
        },
      )
    ],
  ));
}

在这里,我在上面的代码中做了以下事情:

  • 在 Card 的 leading 位置,我使用 Image.asset 显示图片,并设置固定宽度为 100.0
  • Card 的标题将是城市名称。
  • 对于 Card 的 Subtitle,我使用 Column 小部件,它提供了垂直对齐放置小部件的灵活性。我将国家放在前面,然后是人口。
  • 最后但也是最重要的,我在点击任何卡片项时显示 snackbar。snackbar 的代码如下:
    _showSnackBar(BuildContext context, City item) {
      final SnackBar objSnackbar = new SnackBar(
        content: new Text("${item.name} is a city in ${item.country}"),
        backgroundColor: Colors.amber,
      );
      Scaffold.of(context).showSnackBar(objSnackbar);
    }

所以最后,我们得到这个:

教程结束!

关注点

请阅读这些文章。它们可能会为您指明方向。

  1. Flutter — 你可能喜欢它的 5 个理由
  2. Flutter 的革命性之处
  3. 为什么 Flutter 使用 Dart
  4. https://material.io/design/components/cards.html
  5. Github: https://github.com/thatsalok/FlutterExample/tree/master/flutter4_listview

Flutter 教程

  1. Flutter入门:教程1 基础
  2. Flutter 入门:教程 2 – StateFulWidget
  3. Flutter 入门:教程 3 导航

Dart 教程

  1. DART2 Prima Plus - 教程 1
  2. DART2 Prima Plus - 第二课 - LIST
  3. DART2 Prima Plus - 第三课 - MAP

历史

  • 2018年7月18日:初版
© . All rights reserved.