flutter 从ReorderableListView切换到ListView会中断行的交互

2fjabf4q  于 2022-12-27  发布在  Flutter
关注(0)|答案(1)|浏览(121)

我有一个在ListViewReorderableListView之间切换的视图。

Widget _buildList(
  BuildContext context,
  List<ExerciseTemplate> exerciseTemplates, 
  EditWorkoutModel dao,
) {
  if (_isInEditingMode) {
    return ReorderableListView(
      key: ObjectKey('reordeableListView'),
      onReorder: ((oldIndex, newIndex) {
        dao.reorderIndexes(
          oldIndex,
          (oldIndex < newIndex) ? newIndex - 1 : newIndex,
        );
      }),
      padding: const EdgeInsets.only(bottom: 120),
      children: [
        for (var exerciseTemplate in exerciseTemplates)
          Provider(
            key: ObjectKey('${exerciseTemplate.id}_compactExerciseTemplateRow_provider'),
            create: (context) => EditExerciseModel(exerciseTemplate),
            child: CompactExerciseTemplateRow(
              key: ObjectKey('${exerciseTemplate.id}_compactExerciseTemplateRow'),
            ),
          ),
        ],
      );
    } else {
      return ListView.builder(
        key: ObjectKey('listView'),
        itemCount: exerciseTemplates.length,
        padding: const EdgeInsets.only(bottom: 120),
        itemBuilder: (BuildContext context, int index) {
          final exerciseTemplate = exerciseTemplates[index];
          return Provider(
            // Key is needed here to properly handle deleted rows in the ui.
            // Without the key, deleted rows are being shown.
            key: ObjectKey(
                '${exerciseTemplate.id}_exerciseTemplateRow_provider'),
            create: (context) => EditExerciseModel(exerciseTemplate),
            child: ExerciseTemplateRow(
              key: ObjectKey('${exerciseTemplate.id}_exerciseTemplateRow'),
              onDelete: () async {
                await dao.deleteExercise(exerciseTemplate);
                return true;
              },
            ),
          );
        },
      );
    }
  }

两个列表显示相同的数据,但点击一个按钮,切换到ReorderableListView,其中显示了不同小部件的数据,再次点击按钮切换回ListView
但是,来回切换会导致我无法与ListView行中的元素交互。这个问题是在我为ListView中的每个元素添加globalKey后出现的。我需要这个key来正确处理删除行,所以我不能只是再次删除key
如何才能使其工作,在切换到ReorderableListView并返回到ListView后,我可以与行中的小部件交互?

gcuhipw9

gcuhipw91#

从提供商文档复制:https://pub.dev/packages/provider
不要用随时间变化的变量创建对象。
在这种情况下,对象将永远不会在值更改时更新。

int count;

Provider(
  create: (_) => MyModel(count),
  child: ...
)

如果要将可能随时间更改的变量传递给对象,请考虑使用ProxyProvider:

int count;

ProxyProvider0(
  update: (_, __) => MyModel(count),
  child: ...
)

可以使用Global键并在ListViewReorderableListView之间切换,请参见以下示例:https://dartpad.dev/?id=fd39a89b67448d86e682dd2c5ec77453

void main() {
  runApp(const MyApp());
}

class MyApp extends StatelessWidget {
  const MyApp({super.key});
  @override
  Widget build(BuildContext context) {
    return const MaterialApp(
      title: 'Flutter Demo',
      home: MyHomePage(),
    );
  }
}

class MyHomePage extends StatefulWidget {
  const MyHomePage({super.key});

  @override
  State<MyHomePage> createState() => _MyHomePageState();
}

class _MyHomePageState extends State<MyHomePage> {
  bool reOrder = false;
  @override
  Widget build(BuildContext context) {
    return Scaffold(
        appBar: AppBar(
          title: Text(reOrder ? "ReoderableListView" : "ListView"),
        ),
        floatingActionButton: FloatingActionButton(onPressed: () {
          setState(() {
            reOrder = !reOrder;
          });
        }),
        body: MyListView(reOrder));
  }
}

final data = List.generate(10, (index) => {"title": 'item $index', "value": false});

class MyListView extends StatefulWidget {
  final bool reOrder;
  const MyListView(this.reOrder, {super.key});

  @override
  State<MyListView> createState() => _MyListViewState();
}

class _MyListViewState extends State<MyListView> {
  @override
  Widget build(BuildContext context) {
    if (widget.reOrder) {
      return ReorderableListView(
        key: const ObjectKey('reordeableListView'),
        onReorder: (int oldIndex, int newIndex) {
          setState(() {
            if (oldIndex < newIndex) {
              newIndex -= 1;
            }
            final item = data.removeAt(oldIndex);
            data.insert(newIndex, item);
          });
        },
        children: [
          for (var item in data)
            ListTile(
              key: ObjectKey('${item["title"]}_compactExerciseTemplateRow_provider'),
              title: Text(item["title"] as String),
              trailing: Text((item["value"] as bool).toString()),
            ),
        ],
      );
    } else {
      return ListView.builder(
        key: const ObjectKey('listView'),
        itemCount: data.length,
        padding: const EdgeInsets.only(bottom: 120),
        itemBuilder: (BuildContext context, int index) {
          return CheckboxListTile(
            key: ObjectKey('${data[index]["title"]}_exerciseTemplateRow_provider'),
            title: Text(data[index]["title"] as String),
            value: (data[index]["value"] as bool),
            onChanged: (bool? value) {
              setState(() => data[index]["value"] = value!);
            },
          );
        },
      );
    }
  }
}

相关问题