我正在开发一个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(),
);
}
}
型
任何帮助、指导或示例代码都将不胜感激。谢谢你,谢谢
1条答案
按热度按时间wd2eg0qa1#
检查材质类https://api.flutter.dev/flutter/material/ReorderableListView-class.html中可重新排序列表视图的实现