乐于分享
好东西不私藏

Build a Todo App with Flutter(6)

Build a Todo App with Flutter(6)

The ToDo application helps us manage and organize our tasks more easily. Managing tasks using the ToDo app will require us to work with data persistence, user input processing, and state management.

$ flutter create todo --emptyCreating project ....  windows/runner/flutter_window.cpp (created)  windows/runner/utils.h (created)  windows/runner/utils.cpp (created)  windows/runner/runner.exe.manifest (created)  windows/runner/CMakeLists.txt (created)  windows/runner/win32_window.h (created)  windows/runner/Runner.rc (created)  windows/runner/win32_window.cpp (created)  windows/runner/resources/app_icon.ico (created)  windows/runner/main.cpp (created)  windows/runner/resource.h (created)  windows/runner/flutter_window.h (created)  windows/flutter/CMakeLists.txt (created)  windows/.gitignore (created)  windows/CMakeLists.txt (created)  ios/Runner.xcworkspace/contents.xcworkspacedata (created)  ios/Runner.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist (created)  ios/Runner.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings (created)  ios/RunnerTests/RunnerTests.swift (created)  ios/Runner/Info.plist (created)  ios/Runner/Runner-Bridging-Header.h (created)  ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png (created)  ios/Runner/Assets.xcassets/LaunchImage.imageset/README.md (created)  ios/Runner/Assets.xcassets/LaunchImage.imageset/Contents.json (created)  ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@3x.png (created)  ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage.png (created)  ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png (created)  ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png (created)  ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png (created)  ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png (created)  ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png (created)  ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png (created)  ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png (created)  ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png (created)  ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png (created)  ios/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json (created)  ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png (created)  ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png (created)  ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png (created)  ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png (created)  ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png (created)  ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png (created)  ios/Runner/Base.lproj/LaunchScreen.storyboard (created)  ios/Runner/Base.lproj/Main.storyboard (created)  ios/Runner/AppDelegate.swift (created)  ios/Runner/SceneDelegate.swift (created)  ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata (created)  ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist (created)  ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings (created)  ios/Runner.xcodeproj/project.pbxproj (created)  ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme (created)  ios/Flutter/Debug.xcconfig (created)  ios/Flutter/Release.xcconfig (created)  ios/Flutter/AppFrameworkInfo.plist (created)  ios/.gitignore (created)  .gitignore (created)  web/favicon.png (created)  web/index.html (created)  web/manifest.json (created)  web/icons/Icon-maskable-512.png (created)  web/icons/Icon-192.png (created)  web/icons/Icon-maskable-192.png (created)  web/icons/Icon-512.png (created)  macos/Runner.xcworkspace/contents.xcworkspacedata (created)  macos/Runner.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist (created)  macos/RunnerTests/RunnerTests.swift (created)  macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_32.png (created)  macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_16.png (created)  macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_256.png (created)  macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_64.png (created)  macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_512.png (created)  macos/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json (created)  macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_128.png (created)  macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_1024.png (created)  macos/Runner/DebugProfile.entitlements (created)  macos/Runner/Base.lproj/MainMenu.xib (created)  macos/Runner/MainFlutterWindow.swift (created)  macos/Runner/Configs/Debug.xcconfig (created)  macos/Runner/Configs/Release.xcconfig (created)  macos/Runner/Configs/Warnings.xcconfig (created)  macos/Runner/Configs/AppInfo.xcconfig (created)  macos/Runner/AppDelegate.swift (created)  macos/Runner/Info.plist (created)  macos/Runner/Release.entitlements (created)  macos/Runner.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist (created)  macos/Runner.xcodeproj/project.pbxproj (created)  macos/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme (created)  macos/Flutter/Flutter-Debug.xcconfig (created)  macos/Flutter/Flutter-Release.xcconfig (created)  macos/.gitignore (created)  android/app/src/profile/AndroidManifest.xml (created)  android/app/src/main/res/mipmap-mdpi/ic_launcher.png (created)  android/app/src/main/res/mipmap-hdpi/ic_launcher.png (created)  android/app/src/main/res/drawable/launch_background.xml (created)  android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png (created)  android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png (created)  android/app/src/main/res/values-night/styles.xml (created)  android/app/src/main/res/values/styles.xml (created)  android/app/src/main/res/drawable-v21/launch_background.xml (created)  android/app/src/main/res/mipmap-xhdpi/ic_launcher.png (created)  android/app/src/main/AndroidManifest.xml (created)  android/app/src/debug/AndroidManifest.xml (created)  android/settings.gradle.kts (created)  android/gradle/wrapper/gradle-wrapper.properties (created)  android/gradle.properties (created)  android/.gitignore (created)  android/build.gradle.kts (created)  android/app/build.gradle.kts (created)  pubspec.yaml (created)  README.md (created)  lib/main.dart (created)  analysis_options.yaml (created)  .idea/runConfigurations/main_dart.xml (created)  .idea/libraries/Dart_SDK.xml (created)  .idea/libraries/KotlinJavaRuntime.xml (created)  .idea/modules.xml (created)  .idea/workspace.xml (created)  linux/runner/main.cc (created)  linux/runner/CMakeLists.txt (created)  linux/runner/my_application.h (created)  linux/runner/my_application.cc (created)  linux/flutter/CMakeLists.txt (created)  linux/.gitignore (created)  linux/CMakeLists.txt (created)Resolving dependencies... (7.0s)Downloading packages...Got dependencies.Wrote 130 files.All done!You can find general documentation for Flutter at: https://docs.flutter.dev/Detailed API documentation is available at: https://api.flutter.dev/If you prefer video documentation, consider: https://www.youtube.com/c/flutterdevIn order to run your empty application, type:  $ flutter runYour empty application code is in ./lib/main.dart.

Add the boilerplate code below in main.dart to create a basic structure with an AppBar and body using a Scaffold.

void main() {  runApp(const MainApp());}classMainAppextendsStatelessWidget{  const MainApp({super.key});  @override  Widget build(BuildContext context) {return MaterialApp(      home: HomeScreen(),      debugShowCheckedModeBanner: false,      theme: ThemeData(primarySwatch: Colors.indigo),    );  }}

We create a HomeScreen widget to display the home screen of this app.

classHomeScreenextendsStatefulWidget{  const HomeScreen({super.key});  @override  State<HomeScreen> createState() => _HomeScreenState();}class_HomeScreenStateextendsState<HomeScreen{  @override  Widget build(BuildContext context) {return Scaffold(      appBar: AppBar(        title: const Text('Todo App',          style: TextStyle(fontWeight: FontWeight.bold, fontSize: 25),        ),        centerTitle: true,        backgroundColor: Colors.green,        foregroundColor: Colors.white,      ),      body: Container(),    );  }}

We intialize required variables to work with Todos:

class_HomeScreenStateextendsState<HomeScreen{  // List to store tasks  List<String> todoList = [];   // Controller for text input  final TextEditingController _controller = TextEditingController();   // Index to track which task is being edited  int updateIndex = -1  // ...}

Next we create methods to addupdate, and delete tasks in a list.

// Function to add a new task to the list  void addList(String task) {    setState(() {      todoList.add(task);      _controller.clear();    });  }  // Function to update an existing task  void updateListItem(String task, int index) {    setState(() {      todoList[index] = task;// Reset update index      updateIndex = -1;      _controller.clear();    });  }  // Function to delete a task  void deleteItem(int index) {    setState(() {      todoList.removeAt(index);    });  }// ...

We update the UI to receive input from the user.

TextFormField(  // Input field controller  controller: _controller,   decoration: InputDecoration(    focusedBorder: OutlineInputBorder(        borderRadius: BorderRadius.circular(8),        borderSide: BorderSide(          color: Colors.green,        )),    filled: true,// Placeholder text    labelText: 'Create Task....'    labelStyle: TextStyle(      color: Colors.black,      fontWeight: FontWeight.bold,    ),  ),),

We use ListView.builder to display the list of tasks.

ListView.builder(// Number of tasks in the list  itemCount: todoList.length,   itemBuilder: (context, index) {return Card(      shape: RoundedRectangleBorder(        borderRadius: BorderRadius.circular(8),      ),// Card background color      color: Colors.green,       child: Container(        margin: EdgeInsets.only(left: 20),        alignment: Alignment.center,        padding: EdgeInsets.all(10),        child: Row(          children: [            Expanded(              flex: 80,              child: Text(// Display the task text                todoList[index],                 style: TextStyle(                    color: Colors.white,                    fontWeight: FontWeight.bold,                    fontSize: 20),              ),            ),// Edit button            IconButton(              onPressed: () {                setState(() {                  _controller.clear();                  _controller.text = todoList[index];                  updateIndex = index;                });              },              icon: Icon(                Icons.edit,                size: 30,                color: Colors.white,              ),            ),            SizedBox(width: 10),// Delete button            IconButton(              onPressed: () {                deleteItem(index);              },              icon: Icon(                Icons.delete,                size: 30,                color: Colors.white,              ),            ),          ],        ),      ),    );  }),

We use a FloatingActionButton to add an item to the list.

FloatingActionButton(      backgroundColor: Colors.green,      foregroundColor: Colors.white,      onPressed: () {            updateIndex != -1                ? updateListItem(_controller.text, updateIndex) // Update task if editing                : addList(_controller.text); // Add new task      },// Icon changes based on action      child: Icon(updateIndex != -1 ? Icons.edit : Icons.add), ),

We use two IconButton to implement actions such as Edit and Delete.

// Edit buttonIconButton(  onPressed: () {        setState(() {              _controller.clear();              _controller.text = todoList[index];              updateIndex = index;        });  },  icon: Icon(        Icons.edit,        size: 30,        color: Colors.white,  ),),SizedBox(width: 10),// Delete buttonIconButton(  onPressed: () {        deleteItem(index);  },  icon: Icon(        Icons.delete,        size: 30,        color: Colors.white,  ),),