ios開(kāi)發(fā)Flutter構(gòu)建todo?list應(yīng)用
正文
今天,我們將使用 Flutter
構(gòu)建一個(gè)動(dòng)態(tài)的 todo list
的應(yīng)用。
開(kāi)發(fā)完成的效果如下:
我們直接進(jìn)入正題。
基礎(chǔ) Flutter 應(yīng)用腳手架
# create new project flutter create flutter_todo_app # navigate to project cd flutter_todo_app # run flutter flutter run
我們清除文件 lib/main.dart
,從頭開(kāi)始開(kāi)發(fā)。
main.dart 這個(gè)文件是 Flutter 應(yīng)用的入口文件。在這篇文章中,我將僅僅使用這個(gè)文件來(lái)開(kāi)發(fā)。
首先,我們先導(dǎo)入 material
包。
import 'package:flutter/material.dart';
下一步,我們得有一個(gè)主要的方法。在這個(gè)例子中,它將返回 TodoApp
實(shí)例。
void main() => runApp( new TodoApp(), );
這個(gè) TodoApp
應(yīng)該是一個(gè) statelessWidget
。這將會(huì)是我們列表的骨架
class TodoApp extends StatelessWidget { @override Widget build(BuildContext context) { return new MaterialApp( title: 'Todo list', home: new TodoList(), ); } }
正如你所見(jiàn),我返回了一個(gè) MaterialApp
實(shí)例,它具有一個(gè) title
屬性和一個(gè) home
功能。這個(gè) home
函數(shù)返回一個(gè) TodoList
實(shí)例。這個(gè) TodoList
類才是我們控制的列表項(xiàng)。
class TodoList extends StatefulWidget { @override _TodoListState createState() => new _TodoListState(); }
等等,這是什么?所有的掛件都會(huì)調(diào)用一個(gè)狀態(tài)去知道將要發(fā)生什么和渲染什么。在這個(gè)例子中,我們調(diào)用了 _TodoListState
。這將包含應(yīng)用中的列表及其運(yùn)行邏輯。
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 }
接下來(lái),創(chuàng)建列表變量。
final List<Todo> _todos = <Todo>[];
也許你已經(jīng)注意到了,我們定義了這個(gè)列表的類型是 Todo
,但 Flutter
怎么知道 Todo
長(zhǎng)是什么樣呢?
Flutter
并不會(huì)知道,所以我們得創(chuàng)建一個(gè)類來(lái)定義。如下:
class Todo { Todo({required this.name, required this.checked}); final String name; bool checked; }
這跟 typescript
中的類型定義很像。我們告訴 flutter
一個(gè) todo 項(xiàng)應(yīng)該包含什么,什么字段是必須的。在我們的案例中,我們有名字和 checked
兩個(gè)狀態(tài)屬性。
回到 _TodoListState
中,我們開(kāi)始讓我們的掛件展示點(diǎn)東西。
@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)), ); }
讓我們看看上面發(fā)生了什么。我們返回了應(yīng)用的一個(gè)腳手架,在腳手架上,我們添加了一個(gè)包含標(biāo)題的 appBar
的屬性。我們定義了 body
屬性,這將存放 ListView
組件。
在上面代碼片段中,通過(guò) map
方法返回每個(gè)元素的 TodoItem
。
然后,在應(yīng)用的底部,我們定義了一個(gè)按鈕。當(dāng)按鈕被點(diǎn)擊時(shí)候,將調(diào)用 _displayDialog
方法。
到目前為止,我們還需要完成下面的代碼片段:
- 創(chuàng)建
TodoItem
- 定義一個(gè)
_displayDialog
函數(shù) - 定義一個(gè)
_handleTodoChange
函數(shù)
讓我們一個(gè)一個(gè)來(lái)解決。
創(chuàng)建 TodoItem
TodoItem
是我們列表項(xiàng)的單獨(dú)體現(xiàn)。
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)), ); } }
正如你所見(jiàn),我們傳遞一個(gè) todo
和 onTodoChanged
進(jìn)來(lái)。
然后我們定義了一個(gè) TextStyle
去處理列表項(xiàng)是否被勾選。
然后我們使用 ListTile
掛件來(lái)展示內(nèi)容和添加點(diǎn)擊事件。
展示 Dialog 去添加列表項(xiàng)
點(diǎn)擊應(yīng)用的右下角的按鈕,將會(huì)調(diào)起 _displayDialog
方法。
這將調(diào)起一個(gè)帶有文本框的對(duì)話框。當(dāng)點(diǎn)擊確認(rèn)的時(shí)候,將以文本框的內(nèi)容基礎(chǔ)添加一個(gè)新的列表項(xiàng)。
在 _TodoListState
中創(chuàng)建 _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
表明在將來(lái)的某個(gè)時(shí)候?qū)⒎祷貪撛诘闹祷蛘咤e(cuò)誤信息。在我們的案例中,將會(huì)返回用戶輸入的值。
對(duì)話框中有一個(gè)動(dòng)作,就是當(dāng)我們點(diǎn)擊按鈕的時(shí)候,將會(huì)關(guān)閉對(duì)話框并且調(diào)用 _addTodoItem
函數(shù)。
我們看看 _addTodoItem
函數(shù)長(zhǎng)什么樣:
void _addTodoItem(String name) { setState(() { _todos.add(Todo(name: name, checked: false)); }); _textFieldController.clear(); }
這函數(shù)比你想象中的簡(jiǎn)單,是吧。
列表項(xiàng)添加狀態(tài)
最后一部分是,我們應(yīng)該為列表項(xiàng)進(jìn)行標(biāo)記。我們需要一個(gè)處理函數(shù) _handleTodoChange
:
void _handleTodoChange(Todo todo) { setState(() { todo.checked = !todo.checked; }); }
這里我們只是改變了其列表項(xiàng)的狀態(tài)。
完整的代碼如下:
// 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開(kāi)發(fā)Flutter構(gòu)建todo list應(yīng)用的詳細(xì)內(nèi)容,更多關(guān)于ios開(kāi)發(fā)Flutter構(gòu)建todo list的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
iOS中使用UItableviewcell實(shí)現(xiàn)團(tuán)購(gòu)和微博界面的示例
這篇文章主要介紹了iOS中使用UItableviewcell實(shí)現(xiàn)團(tuán)購(gòu)和微博界面的示例,開(kāi)發(fā)語(yǔ)言基于傳統(tǒng)的Objective-C,需要的朋友可以參考下2016-01-01詳解iOS之關(guān)于double/float數(shù)據(jù)計(jì)算精度問(wèn)題
本篇文章主要介紹了iOS之關(guān)于double/float數(shù)據(jù)計(jì)算精度問(wèn)題,小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧2018-02-02iOS中UIView實(shí)現(xiàn)不同方向的導(dǎo)角
這篇文章主要給大家介紹了關(guān)于iOS中UIView實(shí)現(xiàn)不同方向的導(dǎo)角的相關(guān)資料,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家學(xué)習(xí)或使用iOS具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2018-05-05Flutter Widgets MediaQuery控件屏幕信息適配
這篇文章主要為大家介紹了Flutter Widgets 之 MediaQuery控件獲取屏幕信息和屏幕適配示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2022-11-11iOS CAEmitterLayer實(shí)現(xiàn)粒子發(fā)射動(dòng)畫(huà)效果
這篇文章主要為大家詳細(xì)介紹了iOS CAEmitterLayer 實(shí)現(xiàn)粒子發(fā)射動(dòng)畫(huà)效果,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2017-06-06UIMenuController在Cell內(nèi)部無(wú)法顯示的解決辦法(iOS9.2)
這篇文章主要為大家詳細(xì)介紹了UIMenuController在Cell內(nèi)部無(wú)法顯示的解決辦法,感興趣的小伙伴們可以參考一下2016-08-08