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