iT邦幫忙

第 11 屆 iThome 鐵人賽

DAY 2
0
Mobile Development

Flutter 從零開始,Android、iOS一次搞定,重新挑戰。系列 第 2

[Day2] 新增代辦事項實作。

昨天我們做了代辦事項的主頁,我們接下來要新增待辦事項。

第一步驟我們先建立新建事項的頁面,lib/screens/edit_todo_screen.dart

class EditTodoScreen extends StatefulWidget {
  final Function addTodo;

  EditTodoScreen(this.addTodo);

  @override
  _EditTodoScreenState createState() => _EditTodoScreenState();
}

class _EditTodoScreenState extends State<EditTodoScreen> {
  final _form = GlobalKey<FormState>();
  final _descriptionFocusNode = FocusNode();
  Map<String, dynamic> _editTodo = {
    'title': '',
    'description': '',
    'done': false,
  };

  @override
  void initState() {
    super.initState();
  }

  @override
  void dispose() {
    _descriptionFocusNode.dispose();

    super.dispose();
  }

  void _saveForm() {
    final isValid = _form.currentState.validate();
    if (isValid) {
      _form.currentState.save();
      print(_editTodo['title']);
      print(_editTodo['description']);
      widget.addTodo(_editTodo);
      Navigator.of(context).pop();
    }
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text('Edit Todo'),
        actions: <Widget>[
          IconButton(
            icon: Icon(Icons.save),
            onPressed: () {
              _saveForm();
            },
          )
        ],
      ),
      body: Padding(
        padding: const EdgeInsets.all(16.0),
        child: Form(
          key: _form,
          child: ListView(
            children: <Widget>[
              TextFormField(
                autofocus: true,
                decoration: InputDecoration(labelText: 'Title'),
                textInputAction: TextInputAction.next,
                onFieldSubmitted: (_) {
                  FocusScope.of(context).requestFocus(_descriptionFocusNode);
                },
                validator: (value) {
                  if (value.isEmpty) {
                    return 'Please enter a title.';
                  }
                  return null;
                },
                onSaved: (value) {
                  _editTodo['title'] = value;
                },
              ),
              SizedBox(
                height: 20,
              ),
              TextFormField(
                focusNode: _descriptionFocusNode,
                decoration: InputDecoration(
                    labelText: 'Description',
                    border: OutlineInputBorder(),
                    hintText: 'Should be at least 10 characters long.'),
                textInputAction: TextInputAction.done,
                maxLines: 5,
                keyboardType: TextInputType.multiline,
                validator: (value) {
                  if (value.isEmpty) {
                    return 'Please enter a description.';
                  }
                  if (value.length < 10) {
                    return 'Should be at least 10 characters long.';
                  }
                  return null;
                },
                onSaved: (value) {
                  _editTodo['description'] = value;
                },
                onFieldSubmitted: (_) => _saveForm(),
              ),
            ],
          ),
        ),
      ),
    );
  }
}

以上重點:
我用了Form這個Widget,這個Widget可以讓我們取得整個Form裡面的TextFormField的值,我們可以不用一個一個監聽。
要注意的是 Form 需要一個Global Key。然後在saveForm function裡面,我們可以用form.currentState.validate() 來確定表單內的內容都正確輸入,form.currentState.save() 會執行TextFormField 裡 onSaved,讓我們可以正確取得輸入得值。

我用了FocusNode,讓我可以控制它在我要的時間,控制InputField在什麼時間會被Focus,這邊我在輸入完Title按Next時,focus下個欄位。

這頁重點部分大概就這些了,如果有看不懂的部分在留言跟我說一下。

我們回到lib/screens/todos_homepage.dart,讓我們把上面的頁面叫出來,

  appBar: AppBar(
    title: Text('Todos'),
    actions: <Widget>[
      IconButton(
        icon: Icon(Icons.add),
        onPressed: () {
          Navigator.push(
            context,
            MaterialPageRoute(
              builder: (ctx) => EditTodoScreen(_addTodoHandler),
            ),
          );
        },
      )
    ],
  ),

我們在我們的 AppBar 右上加上讓他切換到EditTodoScreen,且會發現EditTodoScreen Widget需要一個function,我在這裡放進_addTodoHandler。

void _addTodoHandler(Map<String, dynamic> newTodo) {
  setState(() {
    todos.add(newTodo);
  });
}

今天大致上就這樣囉!
我把上面 Sourse code 連結附上,怕大家看不懂。

Github: https://github.com/kevinypfan/ithome-todo-project


上一篇
[Day 1] 萬年老梗,卻很實用之待辦清單。
下一篇
[Day3] Flutter 狀態管理之 Provider
系列文
Flutter 從零開始,Android、iOS一次搞定,重新挑戰。12
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言