dart 如何使用Flutter在待办事项列表上实现拖放功能?

rn0zuynd  于 11个月前  发布在  Flutter
关注(0)|答案(1)|浏览(92)

我正在开发一个Flutter应用程序,在那里我有一个使用自定义小部件显示的Todo列表。我想允许用户通过拖放来重新排序待办事项。具体来说,用户应该能够在icon (Icon(Icons.drag_handle))上单击并拖动,以便对列表中的todo项进行重新排序。

// Inside CardTodoWidget
IconButton(
    icon: Icon(Icons.drag_handle),
    onPressed: () {
        // Drag and Drop Logic Here?
    }),

字符串
我的待办事项列表是使用自定义通知程序(TaskList)管理的,我在task_notifier.dart文件中有一个reorderList方法,我认为它可能很有用,但我不确定如何将所有内容联系在一起。
task_notifier.dart

class TaskList extends StateNotifier<List<Todo>> {
  TaskList(this.ref) : super(<Todo>[]);
  final Ref ref;

  static final initialList = <Todo>[
  ];

    void reorderList(List<Todo> reorderedList) {
    state = reorderedList;
  }

void addTask(Todo task) {
  state = [...state, task];
  double taskHeight = calculateTaskHeight(task.title, task.description);
  ref.read(minHeightProvider.notifier).increaseHeight(taskHeight);
}

double calculateTaskHeight(String title, String description) {
  double baseTaskHeight = 350.0;
  double newLineHeight = 15.0;
  int numberOfNewLines = '\n'.allMatches(title + description).length;

  return baseTaskHeight + newLineHeight * numberOfNewLines;
}

  void removeTask(Todo task) {
  double taskHeight = calculateTaskHeight(task.title, task.description);
  ref.read(minHeightProvider.notifier).decreaseHeight(taskHeight);
  state = state.where((element) => element != task).toList();
}

}

final taskListProvider = StateNotifierProvider<TaskList, List<Todo>>((ref) {
  return TaskList(ref);
});

final todoPageHeightProvider = Provider<double>((ref) {
  List<Todo> todos = ref.watch(taskListProvider);
  double minTodoPageHeight = ref.watch(minHeightProvider);
  double todoPageHeight = minTodoPageHeight;

  for (var todo in todos) {
    todoPageHeight += ref.read(taskListProvider.notifier).calculateTaskHeight(todo.title, todo.description);
  }

  print("Current MinTodoPageHeight: $minTodoPageHeight");
  print("Current TodoPageHeight: $todoPageHeight");

  return max(todoPageHeight, 450.0); // Ensuring non-negative height
});

class MinHeight extends StateNotifier<double> {
  double _baseHeight; // Variable to store the base height

  MinHeight() : _baseHeight =350.0, super(450.0); // Initialize with default value

  // Method to increase the base height when a new task is added
 void increaseHeight(double taskHeight) {
  _baseHeight += taskHeight;
  state = _baseHeight;
}

void decreaseHeight(double taskHeight) {
  _baseHeight -= taskHeight;
  state = _baseHeight;
}

 void adjustHeight(String title, String description) {
  double newLineHeight = 15.0;
  int numberOfNewLines = '\n'.allMatches(title + description).length;

  state = _baseHeight + newLineHeight * numberOfNewLines;
}
}

final minHeightProvider = StateNotifierProvider<MinHeight, double>((ref) {
  return MinHeight();
});


我不确定如何继续实现拖放功能。如何将拖动手柄图标与重新排序逻辑绑定在一起,以便可以可视地拖动待办事项并在状态中反映出来?
我将向您展示整个代码以给予上下文:
card_todo_widget.dart

class CardTodoWidget extends ConsumerStatefulWidget {
  const CardTodoWidget({super.key});

  @override
  ConsumerState<ConsumerStatefulWidget> createState() => _CardTodoWidgetState();
}

class _CardTodoWidgetState extends ConsumerState<CardTodoWidget> {
  bool isActive = false;
  List<Todo> todos = [];
  @override
  void dispose() {
    for (var todo in todos) {
      todo.titleController.dispose();
      todo.descriptionController.dispose();
    }
    super.dispose();
  }

  @override
  Widget build(BuildContext context) {
    List<Todo> todos = ref.watch(taskListProvider);
    double todoPageHeight = ref
        .watch(todoPageHeightProvider); // get the todoPageHeight from provider

    return Column(
      children: todos.map((todo) {
        return Padding(
          padding: const EdgeInsets.fromLTRB(23, 8, 23, 16),
          child: Align(
            alignment: Alignment.center,
            child: Glassmorphism(
              blur: 5,
              opacity: 0.2,
              radius: 15,
              child: Container(
                padding: const EdgeInsets.all(8),
                child: Column(
                  crossAxisAlignment: CrossAxisAlignment.stretch,
                  mainAxisAlignment: MainAxisAlignment.spaceAround,
                  children: [
                    Column(
                      crossAxisAlignment: CrossAxisAlignment.start,
                      mainAxisAlignment: MainAxisAlignment.start,
                      children: [
                        Row(
                          mainAxisAlignment: MainAxisAlignment.spaceBetween,
                          crossAxisAlignment: CrossAxisAlignment.start,
                          children: [
                            IconButton(
                                icon: Icon(Icons.drag_handle),
                                onPressed: () {}),
                            Padding(
                              padding: const EdgeInsets.only(right: 10),
                              child: Row(
                                children: [
                                  IconButton(
                                    icon: const Icon(Icons.edit),
                                    onPressed: () {
                                      setState(() {
                                        todo.isEditable = !todo
                                            .isEditable; // Toggle the isEditable flag when the edit button is clicked

                                        if (todo.isEditable) {
                                          todo.originalTitle = todo
                                              .title; // Store the current title as original
                                          todo.originalDescription = todo
                                              .description; // Store the current description as original
                                        }
                                      });
                                    },
                                  ),
                                  IconButton(
                                      icon: const Icon(Icons.delete),
                                      onPressed: () {
                                        setState(() {
                                          ref
                                              .read(taskListProvider.notifier)
                                              .removeTask(todo);
                                        });
                                      }),
                                  SmileFaceCheckbox(
                                      isActive: todo.isActive,
                                      onPress: () {
                                        setState(() {
                                          todo.isActive = !todo.isActive;
                                        });
                                      }),
                                ],
                              ),
                            ),
                          ],
                        ),
                      ],
                    ),
                    Row(
                      mainAxisAlignment: MainAxisAlignment.spaceBetween,
                      children: [
                        Expanded(
                          child: Padding(
                            padding: const EdgeInsets.only(left: 10, right: 10),
                            child: Container(
                              width: 200,
                              child: TextField(
                                controller: todo.titleController,
                                maxLength: 100,
                                style: GoogleFonts.nunito(
                                  color: const Color(0xffFAFAFA),
                                  fontSize: 20.0,
                                  fontWeight: FontWeight.w500,
                                ),
                                decoration: const InputDecoration(
                                  border: InputBorder.none,
                                  hintText:
                                      'Enter task title...', // placeholder text
                                  hintStyle: TextStyle(color: Colors.grey),
                                ),
                                enabled: todo.isEditable,
                                onChanged: (text) {
                                  ref
                                      .read(minHeightProvider.notifier)
                                      .adjustHeight(
                                        text,
                                        todo.descriptionController.text,
                                      );
                                },
                                maxLines: null,
                                minLines: 1,
                                scrollPhysics: const BouncingScrollPhysics(),
                                keyboardType: TextInputType.multiline,
                                // inputFormatters: [],
                                inputFormatters: [
                                  FilteringTextInputFormatter.deny(
                                      RegExp(r'\n'))
                                ],
                              ),
                            ),
                          ),
                        ),
                      ],
                    ),
                    Row(mainAxisAlignment: MainAxisAlignment.start, children: [
                      Expanded(
                        child: Padding(
                          padding: const EdgeInsets.only(left: 10, right: 10),
                          child: Container(
                            width: 200,
                            child: TextField(
                              controller: todo.descriptionController,
                              maxLength: 200,
                              style: GoogleFonts.nunito(
                                color: const Color(0xffFAFAFA),
                                fontSize: 16.0,
                              ),
                              decoration: const InputDecoration(
                                border: InputBorder.none,
                                hintText:
                                    'Enter task description...', // placeholder text
                                hintStyle: TextStyle(color: Colors.grey),
                              ),
                              enabled: todo.isEditable,
                              onChanged: (text) {
                                ref
                                    .read(minHeightProvider.notifier)
                                    .adjustHeight(
                                      todo.titleController.text,
                                      text,
                                    );
                              },
                              maxLines: null,
                              minLines: 1,
                              scrollPhysics: const BouncingScrollPhysics(),
                              keyboardType: TextInputType.multiline,
                              inputFormatters: [
                                NewlineLimitingTextInputFormatter(10),
                              ],
                            ),
                          ),
                        ),
                      ),
                    ]),
                    if (todo.isEditable)
                      Row(
                        mainAxisAlignment: MainAxisAlignment.spaceAround,
                        children: [
                          ElevatedButton(
                            onPressed: () {
                              setState(() {
                                todo.title = todo.titleController.text;
                                todo.description =
                                    todo.descriptionController.text;
                                todo.isEditable = false;
                              });
                            },
                            style: ButtonStyle(
                              backgroundColor: MaterialStateProperty.all<Color>(
                                  Colors.green),
                              foregroundColor: MaterialStateProperty.all<Color>(
                                  Colors.white),
                            ),
                            child: Text(
                              'Save',
                              style: GoogleFonts.nunito(),
                            ),
                          ),
                          ElevatedButton(
                            onPressed: () {
                              setState(() {
                                todo.titleController.text = todo
                                    .originalTitle; // Restore the original title
                                todo.descriptionController.text = todo
                                    .originalDescription; // Restore the original description
                                todo.isEditable = false;
                              });
                            },
                            style: ButtonStyle(
                              backgroundColor:
                                  MaterialStateProperty.all<Color>(Colors.red),
                              foregroundColor: MaterialStateProperty.all<Color>(
                                  Colors.white),
                            ),
                            child: Text(
                              'Cancel',
                              style: GoogleFonts.nunito(),
                            ),
                          ),
                        ],
                      )
                  ],
                ),
              ),
            ),
          ),
        );
      }).toList(),
    );
  }
}


任何帮助、指导或示例代码都将不胜感激。谢谢你,谢谢

相关问题