ios开发Flutter构建todo list应用

目录
  • 正文
    • 基础 Flutter 应用脚手架
    • 创建 TodoItem
    • 展示 Dialog 去添加列表项
    • 列表项添加状态

正文

今天,我们将使用 Flutter 构建一个动态的 todo list 的应用。

开发完成的效果如下:

我们直接进入正题。

基础 Flutter 应用脚手架

# create new project
flutter create flutter_todo_app
# navigate to project
cd flutter_todo_app
# run flutter
flutter run

我们清除文件 lib/main.dart,从头开始开发。

main.dart 这个文件是 Flutter 应用的入口文件。在这篇文章中,我将仅仅使用这个文件来开发。

首先,我们先导入 material 包。

import 'package:flutter/material.dart';

下一步,我们得有一个主要的方法。在这个例子中,它将返回 TodoApp 实例。

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

这个 TodoApp 应该是一个 statelessWidget。这将会是我们列表的骨架

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

正如你所见,我返回了一个 MaterialApp 实例,它具有一个 title 属性和一个 home 功能。这个 home 函数返回一个 TodoList 实例。这个 TodoList 类才是我们控制的列表项。

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

等等,这是什么?所有的挂件都会调用一个状态去知道将要发生什么和渲染什么。在这个例子中,我们调用了 _TodoListState。这将包含应用中的列表及其运行逻辑。

class _TodoListState extends State<TodoList> {
  final TextEditingController _textFieldController = TextEditingController();
  final List<Todo> _todos = <Todo>[];
  @override
  Widget build(BuildContext context) {
	  // Widget template comes here
  }
  // Other functions
}

接下来,创建列表变量。

final List<Todo> _todos = <Todo>[];

也许你已经注意到了,我们定义了这个列表的类型是 Todo,但 Flutter 怎么知道 Todo 长是什么样呢?

Flutter 并不会知道,所以我们得创建一个类来定义。如下:

class Todo {
  Todo({required this.name, required this.checked});
  final String name;
  bool checked;
}

这跟 typescript 中的类型定义很像。我们告诉 flutter 一个 todo 项应该包含什么,什么字段是必须的。在我们的案例中,我们有名字和 checked 两个状态属性。

回到 _TodoListState 中,我们开始让我们的挂件展示点东西。

@override
Widget build(BuildContext context) {
	return new Scaffold(
	  appBar: new AppBar(
	    title: new Text('Todo list'),
	  ),
	  body: ListView(
	    padding: EdgeInsets.symmetric(vertical: 8.0),
	    children: _todos.map((Todo todo) {
	      return TodoItem(
	        todo: todo,
	        onTodoChanged: _handleTodoChange,
	      );
	    }).toList(),
	  ),
	  floatingActionButton: FloatingActionButton(
	      onPressed: () => _displayDialog(),
	      tooltip: 'Add Item',
	      child: Icon(Icons.add)),
	);
}

让我们看看上面发生了什么。我们返回了应用的一个脚手架,在脚手架上,我们添加了一个包含标题的 appBar 的属性。我们定义了 body 属性,这将存放 ListView 组件。

在上面代码片段中,通过 map 方法返回每个元素的 TodoItem

然后,在应用的底部,我们定义了一个按钮。当按钮被点击时候,将调用 _displayDialog 方法。

到目前为止,我们还需要完成下面的代码片段:

  • 创建 TodoItem
  • 定义一个 _displayDialog 函数
  • 定义一个 _handleTodoChange 函数

让我们一个一个来解决。

创建 TodoItem

TodoItem 是我们列表项的单独体现。

class TodoItem extends StatelessWidget {
  TodoItem({
    required this.todo,
    required this.onTodoChanged,
  }) : super(key: ObjectKey(todo));
  final Todo todo;
  final onTodoChanged;
  TextStyle? _getTextStyle(bool checked) {
    if (!checked) return null;
    return TextStyle(
      color: Colors.black54,
      decoration: TextDecoration.lineThrough,
    );
  }
  @override
  Widget build(BuildContext context) {
    return ListTile(
      onTap: () {
        onTodoChanged(todo);
      },
      leading: CircleAvatar(
        child: Text(todo.name[0]),
      ),
      title: Text(todo.name, style: _getTextStyle(todo.checked)),
    );
  }
}

正如你所见,我们传递一个 todoonTodoChanged 进来。

然后我们定义了一个 TextStyle 去处理列表项是否被勾选。

然后我们使用 ListTile 挂件来展示内容和添加点击事件。

展示 Dialog 去添加列表项

点击应用的右下角的按钮,将会调起 _displayDialog 方法。

这将调起一个带有文本框的对话框。当点击确认的时候,将以文本框的内容基础添加一个新的列表项。

_TodoListState 中创建 _displayDialog

Future<void> _displayDialog() async {
	return showDialog<void>(
	  context: context,
	  barrierDismissible: false, // user must tap button!
	  builder: (BuildContext context) {
	    return AlertDialog(
	      title: const Text('Add a new todo item'),
	      content: TextField(
	        controller: _textFieldController,
	        decoration: const InputDecoration(hintText: 'Type your new todo'),
	      ),
	      actions: <Widget>[
	        TextButton(
	          child: const Text('Add'),
	          onPressed: () {
	            Navigator.of(context).pop();
	            _addTodoItem(_textFieldController.text);
	          },
	        ),
	      ],
	    );
	  },
	);
}

Flutter 中的 Future 表明在将来的某个时候将返回潜在的值或者错误信息。在我们的案例中,将会返回用户输入的值。

对话框中有一个动作,就是当我们点击按钮的时候,将会关闭对话框并且调用 _addTodoItem 函数。

我们看看 _addTodoItem 函数长什么样:

void _addTodoItem(String name) {
	setState(() {
	  _todos.add(Todo(name: name, checked: false));
	});
	_textFieldController.clear();
}

这函数比你想象中的简单,是吧。

列表项添加状态

最后一部分是,我们应该为列表项进行标记。我们需要一个处理函数 _handleTodoChange

void _handleTodoChange(Todo todo) {
	setState(() {
	  todo.checked = !todo.checked;
	});
}

这里我们只是改变了其列表项的状态。

完整的代码如下:

// lib/main.dart
import 'package:flutter/material.dart';
class Todo {
  Todo({required this.name, required this.checked});
  final String name;
  bool checked;
}
class TodoItem extends StatelessWidget {
  TodoItem({
    required this.todo,
    required this.onTodoChanged,
  }) : super(key: ObjectKey(todo));
  final Todo todo;
  final onTodoChanged;
  TextStyle? _getTextStyle(bool checked) {
    if (!checked) return null;
    return TextStyle(
      color: Colors.black54,
      decoration: TextDecoration.lineThrough,
    );
  }
  @override
  Widget build(BuildContext context) {
    return ListTile(
      onTap: () {
        onTodoChanged(todo);
      },
      leading: CircleAvatar(
        child: Text(todo.name[0]),
      ),
      title: Text(todo.name, style: _getTextStyle(todo.checked)),
    );
  }
}
class TodoList extends StatefulWidget {
  @override
  _TodoListState createState() => new _TodoListState();
}
class _TodoListState extends State<TodoList> {
  final TextEditingController _textFieldController = TextEditingController();
  final List<Todo> _todos = <Todo>[];
  @override
  Widget build(BuildContext context) {
    return new Scaffold(
      appBar: new AppBar(
        title: new Text('Todo list'),
      ),
      body: ListView(
        padding: EdgeInsets.symmetric(vertical: 8.0),
        children: _todos.map((Todo todo) {
          return TodoItem(
            todo: todo,
            onTodoChanged: _handleTodoChange,
          );
        }).toList(),
      ),
      floatingActionButton: FloatingActionButton(
          onPressed: () => _displayDialog(),
          tooltip: 'Add Item',
          child: Icon(Icons.add)),
    );
  }
  void _handleTodoChange(Todo todo) {
    setState(() {
      todo.checked = !todo.checked;
    });
  }
  void _addTodoItem(String name) {
    setState(() {
      _todos.add(Todo(name: name, checked: false));
    });
    _textFieldController.clear();
  }
  Future<void> _displayDialog() async {
    return showDialog<void>(
      context: context,
      barrierDismissible: false, // user must tap button!
      builder: (BuildContext context) {
        return AlertDialog(
          title: const Text('Add a new todo item'),
          content: TextField(
            controller: _textFieldController,
            decoration: const InputDecoration(hintText: 'Type your new todo'),
          ),
          actions: <Widget>[
            TextButton(
              child: const Text('Add'),
              onPressed: () {
                Navigator.of(context).pop();
                _addTodoItem(_textFieldController.text);
              },
            ),
          ],
        );
      },
    );
  }
}
class TodoApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return new MaterialApp(
      title: 'Todo list',
      home: new TodoList(),
    );
  }
}
void main() => runApp(new TodoApp());

本文采用的是意译的方式。原文链接 - Build a todo list app with Flutter

以上就是ios开发Flutter构建todo list应用的详细内容,更多关于ios开发Flutter构建todo list的资料请关注我们其它相关文章!

时间: 2022-09-25

Flutter使用push&nbsp;pop方法及路由进行导航详解

目录 正文 准备工作 第一种导航方式 第二种导航方式 正文 在 Web/Mobile 应用程序中,导航是一个很重要的特性,因为它允许你从一个页面跳转到另一个页面. 在 flutter 应用程序中,我们可以使用 push(), pop() 方法实现导航,或者编写我们自己的路由. 准备工作 我们假设 FirstScreen 和 SecondScreen 是两个不同的类,分别在各自的 FirstScreen.dart 和 SecondScreen.dart 文件内. FirstScreen.dart

Flutter使用Overlay与ColorFiltered新手引导实现示例

目录 思路 Flutter BlendMode ColorFiltered 实现 获取镂空位置 ColorFiltered child 完整代码 最终效果 小结 思路 开发过程中常见这样的需求,页面中有几个按钮,用户首次进入时需要对这几个按钮高亮展示并加上文字提示.常见的一种方案是找UI切图,那如何完全使用代码来实现呢? 就以Flutter原始Demo页面为例,如果我们需要对中间展示区域以及右下角按钮进行一个引导提示. 我们需要做到的效果是除了红色框内的Widget,其余部分要盖上一层半透明黑色

Flutter GetPageRoute实现嵌套导航学习

目录 1. 嵌套导航-GetPageRoute 2. 自定义拓展 3. 使用bottomNavigationBar 4.小结 1. 嵌套导航-GetPageRoute 本文主要介绍在Getx下快速实现一个嵌套导航 嵌套导航顾名思义,我们导航页面中嵌套一个独立的路由,效果如下 点击跳转 代码如下,也是比较简单 return Scaffold( appBar: AppBar(title: const Text('嵌套导航'),), body: Navigator( key: Get.nestedKe

Flutter 异步编程之单线程下异步模型图文示例详解

目录 一. 本专栏图示概念规范 1. 任务概念规范 2. 任务的状态 3. 时刻与时间线 4.同步与异步 二.理解单线程中的异步任务 1. 任务的分配 2.异步任务特点 3. 异步任务完成与回调 三. Dart 语言中的异步 1.编程语言中与异步模型的对应关系 2.Dart 编程中的异步任务 3.当前任务分析 四.异步模型的延伸 1. 单线程异步模型的局限性 2. 多线程与异步的关系 3. Dart 中如何解决单线程异步模型的局限性 一. 本专栏图示概念规范 本专栏是对 异步编程 的系统探索,会

Flutter EventBus事件总线的应用详解

目录 前言 EventBus的简介 EventBus的实际应用 总结 前言 flutter项目中,有许多可以实现跨组件通讯的方案,其中包括InheritedWidget,Notification,EventBus等.本文主要探讨的是EventBus事件总线实现跨组件通讯的方法. EventBus的简介 EventBus的核心是基于Streams.它允许侦听器订阅事件并允许发布者触发事件,使得不同组件的数据不需要一层层传递,可以直接通过EventBus实现跨组件通讯. EventBus最主要是通过

Flutter入门学习Dart语言变量及基本使用概念

目录 正文 变量 变量的声明赋值 变量的划分 默认值 变量的类型推断修饰符 Late变量 类型判断is和类型转换as 一些重要概念 空安全和可空类型? 表达式和语句 注释 DartPad 正文 Dart是Google发布的开源编程语言,是一种面向对象的语言.其主要应用是Flutter框架开发(Android.IOS),此外,也可以用在服务器.脚本.Web开发中.随着Flutter3.0开始支持全平台开发,Dart也可以实现桌面应用. 关于Dart的介绍不再细说.下面开始Dart的使用介绍 首先记

C、C++、Java到Python,编程入门学习什么语言比较好

摘要:回顾编程语言几十年来的兴衰起伏,似乎也折射了整个信息产业的变迁消亡,想要在技术的洪流里激流勇进,找准并学精一两门编程语言更加显得至关重要. 最近,TIOBE更新了7月的编程语言榜单,常年霸榜的C.Java和Python依然蝉联前三位.万万没想到的是,R语言居然冲到了第八位,创下了史上最佳记录.而且后续随着业内对数据统计和挖掘需求的上涨,R语言热度颇有些势不可挡的架势. 然而作为程序员吃饭的工具,编程语言之间也形成了某种鄙视链,各大论坛里弥漫着剑拔弩张的气氛,众口难调.也难怪有很多初学者会有

JSP自定义标签入门学习

本文为大家分享了JSP自定义标签入门学习教程,希望大家喜欢. 1.JSP自定义标签: 自定义标签是用户定义的JSP语言元素.当JSP页面包含一个自定义标签时将被转化为servlet,标签转化为对被 称为tag handler的对象的操作,即当servlet执行时Web container调用那些操作.JSP标签扩展可以让你创建新的标签并且可以直接插入到一个JSP页面. JSP 2.0规范中引入Simple Tag Handlers来编写这些自定义标记.你可以继承SimpleTagSupport类

mybatis框架入门学习教程

MyBatis是一个支持普通SQL查询,存储过程和高级映射的优秀持久层框架.MyBatis消除了几乎所有的JDBC代码和参数的手工设置以及对结果集的检索封装.MyBatis可以使用简单的XML或注解用于配置和原始映射,将接口和Java的POJO(Plain Old Java Objects,普通的Java对象)映射成数据库中的记录. 1.创建工程,导入jar包 创建一个java工程或者web工程都可以,然后导入mybatis的jar包和依赖包还有数据库的jar包,本人使用Oracle10g数据库

Ajax入门学习教程(一)

1 什么是AJAX AJAX(Asynchronous JavaScript And XML)翻译成中文就是"异步Javascript和XML".即使用Javascript语言与服务器进行异步交互,传输的数据为XML(当然,传输的数据不只是XML). AJAX还有一个最大的特点就是,当服务器响应时,不用刷新整个浏览器页面,而是可以局部刷新.这一特点给用户的感受是在不知不觉中完成请求和响应过程. 与服务器异步交互: 浏览器页面局部刷新: 2. 同步交互与异步交互 同步交互:客户端发出一个

通过GDB学习C语言的讲解

对于那些具有高级编程语言诸如: Ruby.Scheme.Haskell 等背景的人来说,学习 C 语言是具有挑战性的.除了纠结于 C  语言中像手动内存管理和指针等底层特性外,你必须在没有 REPL ( Read-Eval-Print Loop ) 的条件下完成工作.一旦你已经习惯于在 REPL 环境下进行探索性的编程,必须进行"编写-编译-运行"这样循环实在有点令人生厌. 最近我发现其实可以用 GDB 来作为 C 语言的伪 REPL.我一直尝试使用 GDB 作为学习 C 语言的工具,

python列表推导式入门学习解析

这篇文章主要介绍了python列表推导式入门学习解析,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下 一.什么是推导式 推导式是从一个或者多个迭代器快速简洁地创建数据类型的一种方法,它将循环和条件判断结合,从而避免语法冗长的代码,提高代码运行效率.能熟练使用推导式也可以间接说明你已经超越了python初学者的水平. 报错 二.条件推导式 1.语法 ''' value1:如果条件表达式condition成立,返回value1 : 如果条件表达式不成

go语言变量定义用法实例

本文实例讲述了go语言变量定义用法.分享给大家供大家参考.具体如下: var语句定义了一个变量的列表:跟函数的参数列表一样,类型在后面. 复制代码 代码如下: package main import "fmt" var x, y, z int var c, python, java bool func main() {     fmt.Println(x, y, z, c, python, java) } 变量定义可以包含初始值,每个变量对应一个. 如果初始化是使用表达式,则可以省略类

Javascript入门学习资料收集整理篇

Javascript入门学习第一篇 js基础Javascript入门学习第二篇 js类型Javascript入门学习第三篇 js运算Javascript入门学习第四篇 js对象和数组Javascript入门学习第五篇 js函数Javascript入门学习第六篇 js DOM编程Javascript入门学习第七篇 js dom实例操作Javascript入门学习第八篇 js dom节点属性说明Javascript入门学习第九篇 Javascript DOM 总结jQuery基础教程笔记适合js新手

献给php初学者(入门学习经验谈)

1.概要:学习任何语言都需要 多看 多想 多写 多问!!写编程是一种熟能生巧的东西!因为知识就那么多,你看多了就会觉得怎么都一样. 程序员就是炒冷饭的,一遍又一遍.代码多敲几遍就可以闭着眼睛写了,所以企业招聘都会问你写过多少行代码的!!程序员最忌讳浮躁,有时候发现一段程序完全找不出错误,仅仅是因为少了或多了一个符号,程序员需要的是细心,粗心的人当不了程序员! 2.php参考手册是必须熟知的,有的初学者会问一些很基础的问题,其实手册上面都有,所以建议初学者先把手册看了,最好把常用函数抄几遍!!再敲

原生javascript 学习之js变量全面了解

1.变量的命名 方法的命名(驼峰命名法) 全部小写 : 单词与单词之间全部下划线 (my_namespace) 大小写混合 : 第一个单词首字母小写其他单词首字母大写. 规则 首字符 英文字母或下划线 组成   英文字母 数字 下划线 禁忌   JavaScript 关键字 保留字 2. 变量的声明 显示声明   :  var 关键字 陋习         :  没有类型 重复声明 隐式声明 不声明直接赋值 正解        : 先声明 后读写 先赋值 后运算 3. 变量类型 值类型 A) 占