[译] 用 Flutter 写一个待办事项应用

我们将创建我们的应用程序并在 Android 上进行测试,因为这在所有操作系统上都可以完成,所以这些步骤对于 iOS 都是一样的。

Flutter 为不少 IDE 提供插件,包括 Android Studio 和 Visual Studio Code。但是,对于我们简单的应用程序来说,我们完全可以使用命令行和一个简单的文本编辑器完成所有操作。首先,让我们创建我们的应用程序,我们将其称为 flutter_todo

flutter create flutter_todo

Flutter 中这个命令可以创建一个简单的 “Hello World” 风格的应用程序。我们可以在 Android 模拟器中立即测试它。打开 Android Studio,Flutter Doctor 会帮助你进行设置。这里我们要创建一个模拟器,但 Android Studio 要求我们先创建一个项目。所以,让我们使用新创建的 Flutter 项目。选择 导入项目(Gradle,Eclipse ADT 等),然后选择文件夹 ~/dev/flutter_todo/android。完成导入项目后,检查控制台中是否有错误。如果有,使用 Android Studio 修复它们。

现在,我们可以通过 Tools> Android> AVD Manager 来创建模拟器。单击“创建虚拟设备”,选择 Pixel,然后一路选择默认值,直到创建完毕。现在,你可以在列表中看到新设备 —— 双击启动它。模拟器运行后,就可以在上面运行我们的 Flutter 应用程序了。

cd flutter_todo
flutter run

这个应用程序比普通的 Hello World 应用程序更有趣,并且包含一些交互性。点击右下角的按钮屏幕中间的计数器数值会增大。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

Flutter 的 “Hello World” 应用程序

热重载

Flutter 有一个非常有用的热重载功能,就像 React Native 一样。这意味着每次改代码时都不需要重新构建和重新运行应用程序。我们来看看它是如何工作的。

比如我们想要更改 Hello World 应用程序标题栏中的文本。所有代码都位于 lib/main.dart 中。在这个文件中,找到下面这行:

home: new MyHomePage(title: ‘Flutter Demo Home Page’),

然后替换为:

home: new MyHomePage(title: ‘Basic Flutter App’),

保存文件,然后返回运行 flutter run 的命令行。你需要做的就是输入r,这会启动热重载过程。你会注意到在模拟器中,标题已经更改。不仅如此,如果你之前点击过按钮,你会发现到计数器并没有重置成 0。就是这个 stateful hot reload 给开发增加了如此有用的功能。你可以随时调整代码并进行测试,但不需要在每次进行更改后强制返回应用程序的初始界面。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

你可以看到一个标题已更改的 Flutter 的 “Hello World” 应用程序。

Flutter 基础

既然我们知道了如何运行 Flutter 应用程序,那么就该开始编写自己的应用程序了。我们选择经典的待办事项应用程序作为例子。如上所述,我们将使用 Dart 。它肯定不是最著名的语言,但如果你之前使用过 Javascript(特别是 ES2015+),C++ 或 Java,那你将会觉得非常熟悉。

Material Design

Flutter 附带一个软件包,可以帮助快速制作 Material 风格的 App。它提供了一种创建带标题栏和正文的屏幕的简单方法。让我们首先设置一下待办事项应用程序,使它有一个我们应用程序名称的标题栏。

删除 lib/main.dart 中现有的所有代码,并添加以下内容:

// 导入 MaterialApp 和其他组件,我们可以使用它们来快速创建 Material 应用程序
import ‘package:flutter/material.dart’;

// 用 Dart 编写的代码从主函数开始执行,runApp 是 Flutter 的一部分,而且需要组件作为我们 app
// 的容器。在 Flutter 中,
// 万物皆组件。
void main() => runApp(new TodoApp());

// Flutter 中,万物皆组件,甚至是整个 App 本身
class TodoApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return new MaterialApp(
title: ‘Todo List’,
home: new Scaffold(
appBar: new AppBar(
title: new Text(‘Todo List’)
)
),
);
}
}

组件

这一小段代码显示了 Flutter 中一个重要的概念 —— 万物皆组件。我们的整个应用程序是一个组件,其中包含 MaterialApp 组件。Scaffold 是一个组件,它可以帮助我们快速创建合适的 Material 布局,而不用担心手动设置样式。AppBar 是一个接受标题的组件,它会在屏幕顶部创建一个栏,这在应用程序中很常见。在 Android 上,它会将文本左侧对齐,而在 iOS 上,它会将文本居中。

由于我们对应用程序进行了比较大的改动,所以这次热重载将无法正常工作。这次我们需要完全重启应用程序。在命令行中,输入 R —— 注意它是大写的,与热重载不同。你将看到一个带标题栏的简单应用程序。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

Android(Pixel 2)与 iOS(iPhone X)上标题栏样式的区别

Stateless Widgets 和 Stateful Widgets

为了使我们的应用看起来更像一个待办事项应用程序,我们应当展示一些任务。你可能已经注意到我们上面的简单应用程序是一个 StatelessWidget。这意味着无法动态修改。对于我们的待办事项应用程序来说,这并不好,因为待办事项会一直添加和删除。但是,StatelessWidget 可以生成动态的子项,它们是StatefulWidget。让我们从整个 app 容器开始分析我们的有状态功能(待办事项列表容器)。

要创建一个 stateful widget,我们需要两个类 —— 一个用于组件本身,另一个用于创建状态。这个设置允使我们可以轻松保存状态,并能够使用热重载等功能。

为什么一个 stateful widget 需要两个类? 想象一下,我们有一个待办事项列表组件,里面有五个待办事项。当我们往列表中添加另一个事项时,Flutter 会以不同的方式更新屏幕。你可能希望它只是将这一项添加到现有组件中。实际上,它创建了一个全新的组件,并把它同旧的组件进行比较,以确定在屏幕上进行哪些更改。

由于我们在每次更改时都会创建一个新窗口组件,所以我们无法在窗口组件中存储任何状态,因为它会在下一次更改时丢失。这就是为什么我们需要一个单独的 State 类。

下面的代码显示了我们新的有状态应用。它在功能上与我们之前的代码相同,但现在可以轻松更改待办事项列表的内容了。用下面的代码替换 lib/main.dart 的所有内容,并用 R 完全重启。

// 导入 MaterialApp 和其他组件,我们可以使用它们来快速创建 Material 应用程序
import ‘package:flutter/material.dart’;

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

class TodoApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return new MaterialApp(
title: ‘Todo List’,
home: new TodoList()
);
}
}

class TodoList extends StatefulWidget {
@override
createState() => new TodoListState();
}

class TodoListState extends State {
@override
Widget build(BuildContext context) {
return new Scaffold(
appBar: new AppBar(
title: new Text(‘Todo List’)
)
);
}
}

修改状态

现在我们的应用已准备好变得有状态化,我们希望能够添加待办事项。首先,我们要添加一个浮动操作按钮(FAB),它可以添加一个自动生成的任务。一会儿我们会允许用户输入自己的任务。我们所有的更改都在 TodoListState 中。

class TodoListState extends State {
List _todoItems = [];

// 每按一次 + 按钮,都会调用这个方法
void _addTodoItem() {
// Putting our code inside “setState” tells the app that our state has changed, and
// it will automatically re-render the list
setState(() {
int index = _todoItems.length;
_todoItems.add('Item ’ + index.toString());
});
}

// 构建整个待办事项列表
Widget _buildTodoList() {
return new ListView.builder(
itemBuilder: (context, index) {
// itemBuilder 将被自动调用,因为列表需要多次填充其可用空间
// 而这很可能超过我们拥有的待办事项数量。
// 所以,我们需要检查索引是否正确。
if(index < _todoItems.length) {
return _buildTodoItem(_todoItems[index]);
}
},
);
}

// 构建一个待办事项
Widget _buildTodoItem(String todoText) {
return new ListTile(
title: new Text(todoText)
);
}

@override
Widget build(BuildContext context) {
return new Scaffold(
appBar: new AppBar(
title: new Text(‘Todo List’)
),
body: _buildTodoList(),
floatingActionButton: new FloatingActionButton(
onPressed: _addTodoItem,
tooltip: ‘Add task’,
child: new Icon(Icons.add)
),
);
}
}

让我们仔细看看如何添加一个新的待办事项:

  • 用户点击 + 按钮,回调 onPressed 函数,从而触发 _addTodoItem 函数
  • addTodoItem_todoItems 数组中添加一个新的字符串
  • _addTodoItem 中的所有内容都会被包含在 setState 调用中,这个调用会通知应用程序待办事项列表已更新
  • TodoList.createState 会在待办事项列表更新时被触发
  • 这会调用 new TodoListState(),它的构造函数是 build,它会构建一个全新的带有更新了的 TODO 事项的 widget
  • 该应用程序获取此新窗口组件,将其与前一个窗口组件进行比较,并添加新项目而不更改其他项目

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

这个应用程序的第二个界面,可以允许用户添加任务

用户交互

如果用户只能添加自动生成的项目,那么这个应用程序就不是很有用。让我们改变我们的 + 按钮的工作方式,让用户能够指定他们自己的任务。我们希望它打开第二个界面,里面有一个简单的文本框,用户可以在里面输入自己的任务。

添加待办事项

Flutter 可以非常简单地使用 MaterialPageRoute 组件添加第二个界面。这需要一个 builder 函数作为参数。这将返回一个“Scaffold”,你可以从我们现有的界面中认出它。因此,创建第二个界面的布局将和第一个界面相同。

创建页面后,我们需要告诉应用程序如何使用它,并且它应该在另一个界面的顶部触发动画。Flutter 为我们提供了 Navigator 来完成这项工作,它使用了在移动应用程序中很常见的 navigation stack 概念。要添加新屏幕,我们把他 push 到导航堆栈。要删除它,我们就 pop 它。我们会创建一个名为 _pushAddTodoScreen 的新函数,它将处理所有这些任务。然后我们可以修改 floatingActionButtononPressed 方法来调用这个函数。

用下面的代码替换现有的 _addTodoItembuild 函数,并在它们旁边添加新的 _pushAddTodoScreen 函数。按 R 触发完全重启,以确保删除上次自动生成的任务。单击 + 按钮并添加任务,然后按键盘上的 Enter 键。屏幕将会关闭,任务会出现在列表中。

// 添加待办事项现在接受一个字符串,而不是自动生成
void _addTodoItem(String task) {
// 仅在用户实际输入内容时添加任务
if(task.length > 0) {
setState(() => _todoItems.add(task));
}
}

Widget build(BuildContext context) {
return new Scaffold(
appBar: new AppBar(
title: new Text(‘Todo List’)
),
body: _buildTodoList(),
floatingActionButton: new FloatingActionButton(
onPressed: _pushAddTodoScreen, // pressing this button now opens the new screen
tooltip: ‘Add task’,
child: new Icon(Icons.add)
),
);
}

void _pushAddTodoScreen() {
// 将此页面推入任务栈
Navigator.of(context).push(
// MaterialPageRoute 会自动为屏幕条目设置动画
// 并添加后退按钮以关闭它
new MaterialPageRoute(
builder: (context) {
return new Scaffold(
appBar: new AppBar(
title: new Text(‘Add a new task’)
),
body: new TextField(
autofocus: true,
onSubmitted: (val) {
_addTodoItem(val);
Navigator.pop(context); // Close the add todo screen
},
decoration: new InputDecoration(
hintText: ‘Enter something to do…’,
contentPadding: const EdgeInsets.all(16.0)
),
)
);
}
)
);
}

删除待办事项

面试复习笔记

这份资料我从春招开始,就会将各博客、论坛。网站上等优质的Android开发中高级面试题收集起来,然后全网寻找最优的解答方案。每一道面试题都是百分百的大厂面经真题+最优解答。包知识脉络 + 诸多细节。
节省大家在网上搜索资料的时间来学习,也可以分享给身边好友一起学习。

《960页Android开发笔记》

《1307页Android开发面试宝典》

包含了腾讯、百度、小米、阿里、乐视、美团、58、猎豹、360、新浪、搜狐等一线互联网公司面试被问到的题目。熟悉本文中列出的知识点会大大增加通过前两轮技术面试的几率。

《507页Android开发相关源码解析》

只要是程序员,不管是Java还是Android,如果不去阅读源码,只看API文档,那就只是停留于皮毛,这对我们知识体系的建立和完备以及实战技术的提升都是不利的。

真正最能锻炼能力的便是直接去阅读源码,不仅限于阅读各大系统源码,还包括各种优秀的开源库。


《Android学习笔记总结+移动架构视频+大厂面试真题+项目实战源码》点击传送门,即可获取!
07页Android开发相关源码解析》**

只要是程序员,不管是Java还是Android,如果不去阅读源码,只看API文档,那就只是停留于皮毛,这对我们知识体系的建立和完备以及实战技术的提升都是不利的。

真正最能锻炼能力的便是直接去阅读源码,不仅限于阅读各大系统源码,还包括各种优秀的开源库。

[外链图片转存中…(img-7MEh1oWn-1715907657093)]
《Android学习笔记总结+移动架构视频+大厂面试真题+项目实战源码》点击传送门,即可获取!

  • 4
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值