iT邦幫忙

2021 iThome 鐵人賽

DAY 19
0
Modern Web

Flutter web 的奇妙冒險系列 第 19

Day 19 | 萬年範例-TodoList(2)

  • 分享至 

  • xImage
  •  

回到昨天留下的問題

  1. card數太長要怎麼辦
  2. TextFiled 送出後怎麼清除裡面的字

其實只要將 SingleChildScrollView wrap住 center 就可以,SingleChildScrollView可以讓widget超出容器尺寸(以這個例子來說是裝置高度)時將它變成一個滾動式的元件。

從名字上也看得出來他只接受一個child,所以大部分時候都是用在元件較小的情況下使用,但其實還是可以像這次用結合 Column 來接受複數的widgets,但實際上還是有其他widget可以達成這些需求像是 ListView

至於TextFiled 送出後怎麼清除裡面的字,在TextFiled 中有一個參數是 controller 。在 flutter 中蠻多互動的元件都有這個參數,來方便我們對一些互動行為有更多細節的操作,我覺得可以想像成類似 react 的 ref 的感覺。那我們就直接原本的 _MyHomePageState 裡宣告我們的控制器。

final TextEditingController _textEditingController = TextEditingController();

然後將這個 _textEditingController 給我們的 TextFiled

TextField(
    decoration: const InputDecoration(labelText: '待辦事項'),
    onSubmitted: (input) {
      _handleAddNewTodo(input);
    },
    controller: _textEditingController,
  ),

接下來回到 _handleAddNewTodo 這個function裡

void _handleAddNewTodo(String input) {
    setState(() {
      _todoList = [..._todoList, input];
      _textEditingController.text = '';
    });
  }

這時我只要在更新完 _todoList 後將 _textEditingController.text = '' 即可。

那接下來我們就來擴充這個TodoList的功能,為了之後著想所以我們的Todo應該不能只是一個 String ,所以我們先建立一個 class 來表示 Todo 。

首先先建立一個檔案 todo_model.dart

class TodoModel {
  final String content;

  TodoModel({required this.content});
}

然後將原本的 _todoList 改成 List<TodoModel>

List<TodoModel> _todoList = [TodoModel(content: '123')];

然後將剩下的部分都改為使用這個 class

// 迴圈渲染部分
TodoCard(
    todoContent: entity.value.content,
    index: entity.key,
  ),
// setState的部分
_todoList = [..._todoList, TodoModel(content: input)];

然後接下來先來新增移除按鈕的UI

..._todoList.asMap().entries.map(
        (entity) => Row(
          mainAxisAlignment: MainAxisAlignment.center,
          children: [
            TodoCard(
              todoContent: entity.value.content,
              index: entity.key,
            ),
            GestureDetector(
              child: const Icon(Icons.remove),
            )
          ],
        ),
      ),

我們將原本迴圈裡改用 Row 然後新增一個 GestureDetector 包住 Icon

GestureDetector 就是將他的child新增一些事件監聽的功能。Icon 則是一個顯示icon的widget, Icons 則是material 提供的一些常用Icon圖案。

接下來我們就來實作刪除功能

void _handleRemoveTodo(int hashCode) {
    setState(() {
      _todoList =
          _todoList.while((value) => value.hashCode != hashCode).toList();
    });
  }

hashCode 是每個 instance 都有的屬性所以我們就直接拿來當作唯一識別的id。

while 類似於JS的 array.filter 當裡面的function是 ture 時則會回傳這個 value

所以整行的意思就是當 hashCode 不等於我傳入的 hashCode 都要回傳,也就是不回傳我要刪除的那個instance 。

只後再回到 GestureDetector

GestureDetector(
    child: const Icon(Icons.remove),
    onTap: () {
      _handleRemoveTodo(entity.value.hashCode);
    },
  )

這樣我們就能完成了刪除功能了~

https://ithelp.ithome.com.tw/upload/images/20211002/20112906zmxGY8JkXV.png

現在的程式碼開始變得有點複雜,所以還是上傳到github 供大家參考。
https://github.com/zxc469469/flutter_todo_list/tree/Day19


上一篇
Day 18 | 萬年範例-TodoList
下一篇
Day 20 | 萬年範例-TodoList(3)
系列文
Flutter web 的奇妙冒險30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言