在 Flutter 移动应用程序中创建一个列表

了解如何创建 Flutter 应用的界面以及如何在它们之间进行数据传递。

了解如何创建 Flutter 应用的界面以及如何在它们之间进行数据传递。

在 Flutter 移动应用程序中创建一个列表

Flutter 是一个流行的开源工具包,它可用于构建跨平台的应用。在文章《用 Flutter 创建移动应用》中,我已经向大家展示了如何在 Linux 中安装 Flutter 并创建你的第一个应用。而这篇文章,我将向你展示如何在你的应用中添加一个列表,点击每一个列表项可以打开一个新的界面。这是移动应用的一种常见设计方法,你可能以前见过的,下面有一个截图,能帮助你对它有一个更直观的了解:

测试 Flutter 应用

Flutter 使用 Dart 语言。在下面的一些代码片段中,你会看到以斜杠开头的语句。两个斜杠(//)是指代码注释,用于解释某些代码片段。三个斜杠(///)则表示的是 Dart 的文档注释,用于解释 Dart 类和类的属性,以及其他的一些有用的信息。

查看Flutter应用的主要部分

Flutter 应用的典型入口点是 main() 函数,我们通常可以在文件 lib/main.dart 中找到它:

“`
void main() {
runApp(MyApp());
}

“`

应用启动时,main() 会被调用,然后执行 MyApp()MyApp 是一个无状态微件(StatelessWidget),它包含了MaterialApp() 微件中所有必要的应用设置(应用的主题、要打开的初始页面等):

“`
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
title: ‘Flutter Demo’,
theme: ThemeData(
primarySwatch: Colors.blue,
visualDensity: VisualDensity.adaptivePlatformDensity,
),
home: MyHomePage(title: ‘Flutter Demo Home Page’),
);
}
}

“`

生成的 MyHomePage() 是应用的初始页面,是一个有状态的微件,它包含包含可以传递给微件构造函数参数的变量(从上面的代码看,我们传了一个 title 变量给初始页面的构造函数):

“`
class MyHomePage extends StatefulWidget {
MyHomePage({Key key, this.title}) : super(key: key);

final String title;

@override
_MyHomePageState createState() => _MyHomePageState();
}

“`

有状态微件(StatefulWidget)表示这个微件可以拥有自己的状态:_MyHomePageState。调用 _MyHomePageState 中的 setState() 方法,可以重新构建用户界面:

“`
class _MyHomePageState extends State {
int _counter = 0; // Number of taps on + button.

void _incrementCounter() { // Increase number of taps and update UI by calling setState().
setState(() {
_counter++;
});
}

}

“`

不管是有状态的,还是无状态的微件,它们都有一个 build() 方法,该方法负责微件的 UI 外观。

“`
@override
Widget build(BuildContext context) {
return Scaffold( // Page widget.
appBar: AppBar( // Page app bar with title and back button if user can return to previous screen.
title: Text(widget.title), // Text to display page title.
),
body: Center( // Widget to center child widget.
child: Column( // Display children widgets in column.
mainAxisAlignment: MainAxisAlignment.center,
children: [
Text( // Static text.
‘You have pushed the button this many times:’,
),
Text( // Text with our taps number.
‘$_counter’, // $ sign allows us to use variables inside a string.
style: Theme.of(context).textTheme.headline4,// Style of the text, “Theme.of(context)” takes our context and allows us to access our global app theme.
),
],
),
),
// Floating action button to increment _counter number.
floatingActionButton: FloatingActionButton(
onPressed: _incrementCounter,
tooltip: ‘Increment’,
child: Icon(Icons.add),
),
);
}

“`

修改你的应用

一个好的做法是,把 main() 方法和其他页面的代码分开放到不同的文件中。要想将它们分开,你需要右击 lib 目录,然后选择 “New > Dart File” 来创建一个 .dart 文件:

创建一个新的 Dart 文件

将新建的文件命名为 items_list_page

切换回到 main.dart 文件,将 MyHomePage_MyHomePageState 中的代码,剪切并粘贴到我们新建的文件。然后将光标放到 StatefulWidget 上(下面红色的下划线处), 按 Alt+Enter 后出现下拉列表,然后选择 package:flutter/material.dart

导入 Flutter 包

经过上面的操作我们将 flutter/material.dart 包添加到了 main.dart 文件中,这样我们就可以使用 Flutter 提供的默认的 material 主题微件。

然后, 在类名 MyHomePage 右击,“Refactor > Rename…”将其重命名为 ItemsListPage

重命名 StatefulWidget 类

Flutter 识别到你重命名了 StatefulWidget 类,它会自动将它的 State 类也跟着重命名:

State 类被自动重命名

回到 main.dart 文件,将文件名 MyHomePage 改为 ItemsListPage。 一旦你开始输入, 你的 Flutter 集成开发环境(可能是 IntelliJ IDEA 社区版、Android Studio 和 VS Code 或 VSCodium),会给出自动代码补完的建议。

IDE 建议自动补完的代码

按回车键即可完成输入,缺失的导入语句会被自动添加到文件的顶部。

添加缺失的导入语句

到此,你已经完成了初始设置。现在你需要在 lib 目录创建一个新的 .dart 文件,命名为 item_model。(注意,类命是大写驼峰命名,一般的文件名是下划线分割的命名。)然后粘贴下面的代码到新的文件中:

“`
/// Class that stores list item info:
/// [id] – unique identifier, number.
/// – icon to display in UI.
/// [title] – text title of the item.
/// [description] – text description of the item.
class ItemModel {
// class constructor
ItemModel(this.id, this.icon, this.title, this.description);

// class fields
final int id;
final IconData icon;
final String title;
final String description;
}

“`

回到 items_list_page.dart 文件,将已有的 _ItemsListPageState 代码替换为下面的代码:

“`
class _ItemsListPageState extends State {

// Hard-coded list of [ItemModel] to be displayed on our page.
final List items = [
ItemModel(0, Icons.account
balance, ‘Balance’, ‘Some info’),
ItemModel(1, Icons.accountbalancewallet, ‘Balance wallet’, ‘Some info’),
ItemModel(2, Icons.alarm, ‘Alarm’, ‘Some info’),
ItemModel(3, Icons.mylocation, ‘My location’, ‘Some info’),
ItemModel(4, Icons.laptop, ‘Laptop’, ‘Some info’),
ItemModel(5, Icons.backup, ‘Backup’, ‘Some info’),
ItemModel(6, Icons.settings, ‘Settings’, ‘Some info’),
ItemModel(7, Icons.call, ‘Call’, ‘Some info’),
ItemModel(8, Icons.restore, ‘Restore’, ‘Some info’),
ItemModel(9, Icons.camera
alt, ‘Camera’, ‘Some info’),
];

@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(widget.title),
),
body: ListView.builder( // Widget which creates [ItemWidget] in scrollable list.
itemCount: items.length, // Number of widget to be created.
itemBuilder: (context, itemIndex) => // Builder function for every item with index.
ItemWidget(
items[itemIndex], () {
_onItemTap(context, itemIndex);
}),
));
}

// Method which uses BuildContext to push (open) new MaterialPageRoute (representation of the screen in Flutter navigation model) with ItemDetailsPage (StateFullWidget with UI for page) in builder.
onItemTap(BuildContext context, int itemIndex) {
Navigator.of(context).push(MaterialPageRoute(
builder: (context) => ItemDetailsPage(
items[itemIndex])));
}
}

// StatelessWidget with UI for our ItemModel-s in ListView.
class ItemWidget extends StatelessWidget {
const ItemWidget(this.model, this.onItemTap, {Key key}) : super(key: key);

final ItemModel model;
final Function onItemTap;

@override
Widget build(BuildContext context) {
return InkWell( // Enables taps for child and add ripple effect when child widget is long pressed.
onTap: onItemTap,
child: ListTile( // Useful standard widget for displaying something in ListView.
leading: Icon(model.icon),
title: Text(model.title),
),
);
}
}

“`

为了提高代码的可读性,可以考虑将 ItemWidget 作为一个单独的文件放到 lib 目录中。

现在唯一缺少的是 ItemDetailsPage 类。在 lib 目录中我们创建一个新文件并命名为 item_details_page。然后将下面的代码拷贝进去:

“`
import ‘package:flutter/material.dart’;

import ‘item_model.dart’;

/// Widget for displaying detailed info of [ItemModel]
class ItemDetailsPage extends StatefulWidget {
final ItemModel model;

const ItemDetailsPage(this.model, {Key key}) : super(key: key);

@override
_ItemDetailsPageState createState() => _ItemDetailsPageState();
}

class _ItemDetailsPageState extends State {
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(widget.model.title),
),
body: Center(
child: Column(
children: [
const SizedBox(height: 16),
Icon(
widget.model.icon,
size: 100,
),
const SizedBox(height: 16),
Text(
‘Item description: ${widget.model.description}’,
style: TextStyle(fontSize: 18),
)
],
),
),
);
}
}

“`

上面的代码几乎没什么新东西,不过要注意的是 _ItemDetailsPageState 里使用了 widget.item.title 这样的语句,它让我们可以从有状态类中引用到其对应的微件(StatefulWidget)。

添加一些动画

现在让我们来添加一些基础的动画:

  1. 找到 ItemWidget 代码块(或者文件)
  2. 将光标放到 build() 方法中的 Icon() 微件上
  3. Alt+Enter,然后选择“Wrap with widget…”

查看微件选项

输入 Hero,然后从建议的下拉列表中选择 Hero((Key key, @required this, tag, this.create))

查找 Hero 微件

下一步, 给 Hero 微件添加 tag 属性 tag: model.id

在 Hero 微件上添加 tag 属性为 model.id

最后我们在 item_details_page.dart 文件中做相同的修改:

测试 Flutter 应用

收尾

这篇教程,让你学到了:

  • 一些符合标准的,且能用于自动创建应用的组件。
  • 如何添加多个页面以及在页面间传递数据。
  • 如何给多个页面添加简单的动画。

如果你想了解更多,查看 Flutter 的 文档(有一些视频和样例项目的链接,还有一些创建 Flutter 应用的“秘方”)与 源码,源码的开源许可证是 BSD 3。


via: https://opensource.com/article/20/11/flutter-lists-mobile-app

作者:Vitaly Kuprenko 选题:lujun9972 译者:ywxgod 校对:wxy

本文由 LCTT 原创编译,Linux中国 荣誉推出

主题测试文章,只做测试使用。发布者:eason,转转请注明出处:https://aicodev.cn/2021/06/01/%e5%9c%a8-flutter-%e7%a7%bb%e5%8a%a8%e5%ba%94%e7%94%a8%e7%a8%8b%e5%ba%8f%e4%b8%ad%e5%88%9b%e5%bb%ba%e4%b8%80%e4%b8%aa%e5%88%97%e8%a1%a8/

Like (0)
eason的头像eason
Previous 2021年6月1日
Next 2021年6月1日

相关推荐

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

联系我们

400-800-8888

在线咨询: QQ交谈

邮件:admin@example.com

工作时间:周一至周五,9:30-18:30,节假日休息

关注微信