Множественный Глобальный Ключ

#flutter #dart #key

Вопрос:

Я новичок в Flutter, и мне нужна помощь для чайников. Потому что каждый раз, когда я перемещаю свой переупорядочиваемый список, мой терминал отправляет мне сообщение «Возникло еще одно исключение: несколько виджетов использовали один и тот же глобальный ключ».

 import 'package:flutter/material.dart';
import 'package:flutter/widgets.dart';
import 'package:todoapp2/models/global.dart';
import 'package:todoapp2/models/widgets/intray_todo_widget.dart';
import 'package:todoapp2/models/classes/task.dart';

class IntrayPage extends StatefulWidget {
  @override
  _IntrayPageState createState() => _IntrayPageState();
}

class _IntrayPageState extends State<IntrayPage> {
  List<Task> taskList = [];
  @override
  Widget build(BuildContext context) {
    taskList = getList();
    return Container(
      color: darkGreyColor,
      child: _buildReorderableListSimple(context),
      // child: ReorderableListView(
      //   padding: EdgeInsets.only(top: 300),
      //   children: todoItems,
      //   onReorder: _onReorder,
      // ),
    );
  }

  Widget _buildListTile(BuildContext context, Task item) {
    return ListTile(
      key: Key(item.taskId),
      title: IntrayTodo(
        title: item.title, keyValue: '',
      ),
    );
  }

  Widget _buildReorderableListSimple(BuildContext context) {
    return Theme(
      data: ThemeData(
          canvasColor: Colors.transparent
      ),
      child: ReorderableListView(
        // handleSide: ReorderableListSimpleSide.Right,
        // handleIcon: Icon(Icons.access_alarm),
        padding: EdgeInsets.only(top: 200.0),
        children: taskList.map((Task item) => _buildListTile(context, item)).toList(),
        onReorder: (oldIndex, newIndex) {
          setState(() {
            Task item = taskList[oldIndex];
            taskList.remove(item);
            taskList.insert(newIndex, item);
          });
        },
      ),
    );
  }

  void _onReorder(int oldIndex, int newIndex) {
    setState(() {
      if (newIndex > oldIndex) {
        newIndex -= 1;
      }
      final Task item = taskList.removeAt(oldIndex);
      taskList.insert(newIndex, item);
    });
  }

  List<Task> getList() {
    for (int i = 0; i < 10; i  ) {
      taskList.add(Task("My first todo "   i.toString(), false, i.toString()));
    }
    return taskList;
  }

}
 

А теперь мое второе досье

 import 'package:flutter/material.dart';

import '../global.dart';


class IntrayTodo extends StatelessWidget {
  final String title;
  final String keyValue;
  IntrayTodo({required this.keyValue, required this.title});
  @override
  Widget build(BuildContext context) {
    return Container(
      key: Key(keyValue),
      margin: EdgeInsets.only(bottom: 5),
      padding: EdgeInsets.all(10),
      height: 100,
      decoration: BoxDecoration(
        color: Colors.blue,
        borderRadius: BorderRadius.all(Radius.circular(10)),
        boxShadow: [
          new BoxShadow(
            color: Colors.black.withOpacity(0.5),
            blurRadius: 10.0,
          ),
        ],
      ),
      child: Row(
        children: <Widget>[
         /* Radio(

          ),*/
          Row(
            children: <Widget>[
              Text(title, style: darkTodoTitle,)
            ],
          )
        ],
      ),
    );
  }

}
 

Образ того, что я пытаюсь сделать

Мое «приложение» работает (глючит из-за ключевой проблемы), это простое приложение для выполнения задач, потому что я пытаюсь учиться и пытаюсь поддерживать свой мозг в форме. Я не знаю, как решить эту проблему. Я очень много гуглил, но ничего не понял, так что это мой последний вариант спросить вас в надежде, что кто-нибудь сможет помочь. Куда мне положить ключ? Я где-то читал «в методе», но я этого не понял.

Код ошибки:

 When the exception was thrown, this was the stack:
#2      RenderObject._getSemanticsForParent
(package:flutter/src/rendering/object.dart:2653:12)
#3      RenderObject._getSemanticsForParent.<anonymous closure>
(package:flutter/src/rendering/object.dart:2675:61)
#4      ContainerRenderObjectMixin.visitChildren
(package:flutter/src/rendering/object.dart:3331:14)
#5      RenderSliverMultiBoxAdaptor.visitChildrenForSemantics
(package:flutter/src/rendering/sliver_multi_box_adaptor.dart:398:11)
#6      RenderObject._getSemanticsForParent
(package:flutter/src/rendering/object.dart:2670:5)
#7      RenderObject._getSemanticsForParent.<anonymous closure>
(package:flutter/src/rendering/object.dart:2675:61)
#8      RenderObjectWithChildMixin.visitChildren
(package:flutter/src/rendering/object.dart:3048:14)
#9      RenderObject.visitChildrenForSemantics
(package:flutter/src/rendering/object.dart:2760:5)
#10     RenderObject._getSemanticsForParent
(package:flutter/src/rendering/object.dart:2670:5)
#11     RenderObject._getSemanticsForParent.<anonymous closure>
(package:flutter/src/rendering/object.dart:2675:61)
#12     Iterable.forEach (dart:core/iterable.dart:257:30)
#13     RenderViewportBase.visitChildrenForSemantics
(package:flutter/src/rendering/viewport.dart:222:10)
#14     RenderObject._getSemanticsForParent
(package:flutter/src/rendering/object.dart:2670:5)
#15     RenderObject._getSemanticsForParent.<anonymous closure>
(package:flutter/src/rendering/object.dart:2675:61)
#16     RenderIgnorePointer.visitChildrenForSemantics
(package:flutter/src/rendering/proxy_box.dart:3266:14)
#17     RenderObject._getSemanticsForParent
(package:flutter/src/rendering/object.dart:2670:5)
#18     RenderObject._getSemanticsForParent.<anonymous closure>
(package:flutter/src/rendering/object.dart:2675:61)
#19     RenderObjectWithChildMixin.visitChildren
(package:flutter/src/rendering/object.dart:3048:14)
#20     RenderObject.visitChildrenForSemantics
(package:flutter/src/rendering/object.dart:2760:5)
#21     RenderSemanticsAnnotations.visitChildrenForSemantics
(package:flutter/src/rendering/proxy_box.dart:4663:11)
#22     RenderObject._getSemanticsForParent
(package:flutter/src/rendering/object.dart:2670:5)
#23     RenderObject._getSemanticsForParent.<anonymous closure>
(package:flutter/src/rendering/object.dart:2675:61)
#24     RenderObjectWithChildMixin.visitChildren
(package:flutter/src/rendering/object.dart:3048:14)
#25     RenderObject.visitChildrenForSemantics
(package:flutter/src/rendering/object.dart:2760:5)
#26     RenderObject._getSemanticsForParent
(package:flutter/src/rendering/object.dart:2670:5)
#27     RenderObject._getSemanticsForParent.<anonymous closure>
(package:flutter/src/rendering/object.dart:2675:61)
#28     RenderObjectWithChildMixin.visitChildren
(package:flutter/src/rendering/object.dart:3048:14)
#29     RenderObject.visitChildrenForSemantics
(package:flutter/src/rendering/object.dart:2760:5)
#30     RenderObject._getSemanticsForParent
(package:flutter/src/rendering/object.dart:2670:5)
#31     RenderObject._getSemanticsForParent.<anonymous closure>
(package:flutter/src/rendering/object.dart:2675:61)
#32     RenderObjectWithChildMixin.visitChildren
(package:flutter/src/rendering/object.dart:3048:14)
#33     RenderObject.visitChildrenForSemantics
(package:flutter/src/rendering/object.dart:2760:5)
#34     RenderObject._getSemanticsForParent
(package:flutter/src/rendering/object.dart:2670:5)
#35     RenderObject._getSemanticsForParent.<anonymous closure>
(package:flutter/src/rendering/object.dart:2675:61)
#36     RenderObjectWithChildMixin.visitChildren
(package:flutter/src/rendering/object.dart:3048:14)
#37     RenderObject.visitChildrenForSemantics
(package:flutter/src/rendering/object.dart:2760:5)
#38     RenderObject._getSemanticsForParent
(package:flutter/src/rendering/object.dart:2670:5)
#39     RenderObject._updateSemantics
(package:flutter/src/rendering/object.dart:2631:41)
#40     PipelineOwner.flushSemantics
(package:flutter/src/rendering/object.dart:1076:16)
#41     RendererBinding.drawFrame
(package:flutter/src/rendering/binding.dart:467:21)
#42     WidgetsBinding.drawFrame
(package:flutter/src/widgets/binding.dart:876:13)
#43     RendererBinding._handlePersistentFrameCallback
(package:flutter/src/rendering/binding.dart:328:5)
#44     SchedulerBinding._invokeFrameCallback
(package:flutter/src/scheduler/binding.dart:1144:15)
#45     SchedulerBinding.handleDrawFrame
(package:flutter/src/scheduler/binding.dart:1082:9)
#46     SchedulerBinding._handleDrawFrame
(package:flutter/src/scheduler/binding.dart:998:5)
#50     _invoke (dart:ui/hooks.dart:163:10)
#51     PlatformDispatcher._drawFrame (dart:ui/platform_dispatcher.dart:259:5)
#52     _drawFrame (dart:ui/hooks.dart:126:31)
(elided 5 frames from class _AssertionError and dart:async)

Another exception was thrown: Duplicate GlobalKey detected in widget tree.

Another exception was thrown: Multiple widgets used the same GlobalKey.

Another exception was thrown: Multiple widgets used the same GlobalKey.

Another exception was thrown: Multiple widgets used the same GlobalKey.

Another exception was thrown: Multiple widgets used the same GlobalKey.
 

Ответ №1:

Клавиши во флаттере должны быть уникальными. Но в вашем примере кода при перестройке виджета используется тот же ключ с тем же значением.

Что происходит, когда вы создаете ключ, flutter сохраняет его (не как переменную области действия, которая удаляется при выполнении функции), а когда виджет перестраивается, flutter пытается создать новый ключ с тем же значением и обнаруживает, что есть старый ключ с тем же значением, что приводит к этой ошибке

Лучше, если вы определили свои ключи вне функции сборки. Нравится

 final Key _key = Key('unique_key');

@override
  Widget build(BuildContext context) {
  .
  .
  .
 

Редактировать: Как здесь упоминалось, ReordarableLitView
Вы можете реорганизовать свой код, чтобы он выглядел так,
чтобы IntrayPage изменить дочерние элементы списка, чтобы они выглядели так

 children: <Widget>[
        for (int index = 0; index < taskList.length; index  )
          _buildListTile(context, taskList[index], index) 
      ],
 

Измените _buildListTile, чтобы получить индекс и отправить его в IntrayTodo виджет

 Widget _buildListTile(BuildContext context, Task item, int index) {
    return ListTile(
      key: Key(item.taskId),
      title: IntrayTodo(
        title: item.title, keyValue: '$index',
      ),
    );
  }
 

Комментарии:

1. Спасибо за ваш комментарий, но я не знаю, как реализовать ваш код, если я попытаюсь сделать ключ в верхней части этого виджета и удалить другие ключи, возникнет огромная ошибка, как и раньше. Это не ваш код, это потому, что я не знаю, как это сделать правильно. Не могли бы вы помочь мне немного больше, если у вас есть время? Эта ключевая проблема действительно трудна для меня…

2. Я просто не понимаю, зачем тебе вообще нужны ключи. приложение будет отлично работать без каких-либо ключей

3. Это приложение для задач, и я хотел сделать переупорядочиваемый список, в котором я могу перетаскивать контейнер с «задачей», и я где-то читал, что они сделали это с помощью ключей. Если у вас есть лучший способ сделать это, просто скажите мне, и я постараюсь это сделать 😀 Это мой самый первый проект.

4. Another exception was thrown: All children of this widget must have a key. Это ошибка, когда я удаляю ключи

5. Если я прокручу вниз, после пятого задания, он вызовет у меня ту же ошибку. Он все еще работает, но он глючит, приложение не выходит из строя, и я вижу дисплей, но если я перетащу одну задачу из бота наверх или прокрутю вниз в этот момент, я увижу ту же ошибку. Спасибо вам за вашу помощь, правда. Я думаю, что я слишком плох, я не знаю. Это «только» список, черт возьми