Вызов дочерней функции из родительской. Функция не отображается публично даже после добавления ссылки

#flutter

#трепетать

Вопрос:

Я хочу вызвать эту функцию addPresetToList() из другого parent widget . Я импортировал AnimatedListWidget (дочерний виджет) в parent widget . Но все равно функция не видна и общедоступна. В чем может быть проблема? и what are the other ways вызывать функции, которые находятся внутри другого класса? Я не могу разделить function их на разные class и call it , как это требуется для получения данных, например: _selectedItem и т. Д.

 void addPresetToList() {  final int index =  _selectedItem == null ? _list.length : _list.indexOf(_selectedItem!);  _list.insert(index, _nextItem  );  }  

Это полный код виджета списка, который содержит приведенный выше код

 import 'package:flutter/material.dart';  // void main() { // runApp(const AnimatedListSample()); // }  class AnimatedListWidget extends StatefulWidget {  const AnimatedListWidget({Key? key}) : super(key: key);   @override  Statelt;AnimatedListWidgetgt; createState() =gt; _AnimatedListWidgetState(); }  class _AnimatedListWidgetState extends Statelt;AnimatedListWidgetgt; {  final GlobalKeylt;AnimatedListStategt; _listKey = GlobalKeylt;AnimatedListStategt;();  late ListModellt;intgt; _list;  int? _selectedItem;  late int  _nextItem; // The next item inserted when the user presses the ' ' button.   @override  void initState() {  super.initState();  _list = ListModellt;intgt;(  listKey: _listKey,  initialItems: lt;intgt;[0, 1, 2],  removedItemBuilder: _buildRemovedItem,  );  _nextItem = 3;  }   // Used to build list items that haven't been removed.  Widget _buildItem(  BuildContext context, int index, Animationlt;doublegt; animation) {  return CardItem(  animation: animation,  item: _list[index],  selected: _selectedItem == _list[index],  onTap: () {  setState(() {  _selectedItem = _selectedItem == _list[index] ? null : _list[index];  });  },  );  }    Widget _buildRemovedItem(  int item, BuildContext context, Animationlt;doublegt; animation) {  return CardItem(  animation: animation,  item: item,  // No gesture detector here: we don't want removed items to be interactive.  );  }  // class AddRemoveListItems {  // Insert the "next item" into the list model.  void addPresetToList() {  final int index =  _selectedItem == null ? _list.length : _list.indexOf(_selectedItem!);  _list.insert(index, _nextItem  );  }   // Remove the selected item from the list model.  void remove() {  if (_selectedItem != null) {  _list.removeAt(_list.indexOf(_selectedItem!));  setState(() {  _selectedItem = null;  });  }  }  // }  @override  Widget build(BuildContext context) {  return Scaffold(  body: Padding(  padding: const EdgeInsets.all(16.0),  //child: Expanded(  child: SingleChildScrollView(  child: Expanded(  child: AnimatedList(  shrinkWrap: true,  key: _listKey,  initialItemCount: _list.length,  itemBuilder: _buildItem,  ),  ))));  } }     typedef RemovedItemBuilderlt;Tgt; = Widget Function(  T item, BuildContext context, Animationlt;doublegt; animation);    class ListModellt;Egt; {  ListModel({  required this.listKey,  required this.removedItemBuilder,  Iterablelt;Egt;? initialItems,  }) : _items = Listlt;Egt;.from(initialItems ?? lt;Egt;[]);   final GlobalKeylt;AnimatedListStategt; listKey;  final RemovedItemBuilderlt;Egt; removedItemBuilder;  final Listlt;Egt; _items;   AnimatedListState? get _animatedList =gt; listKey.currentState;   void insert(int index, E item) {  _items.insert(index, item);  _animatedList!.insertItem(index);  }   E removeAt(int index) {  final E removedItem = _items.removeAt(index);  if (removedItem != null) {  _animatedList!.removeItem(  index,  (BuildContext context, Animationlt;doublegt; animation) {  return removedItemBuilder(removedItem, context, animation);  },  );  }  return removedItem;  }   int get length =gt; _items.length;   E operator [](int index) =gt; _items[index];   int indexOf(E item) =gt; _items.indexOf(item); }    class CardItem extends StatelessWidget {  const CardItem({  Key? key,  this.onTap,  this.selected = false,  required this.animation,  required this.item,  }) : assert(item gt;= 0),  super(key: key);   final Animationlt;doublegt; animation;  final VoidCallback? onTap;  final int item;  final bool selected;   @override  Widget build(BuildContext context) {  TextStyle textStyle = Theme.of(context).textTheme.headline4!;  if (selected) {  textStyle = textStyle.copyWith(color: Colors.lightGreenAccent[400]);  }  return Padding(  padding: const EdgeInsets.all(2.0),  child: SizeTransition(  sizeFactor: animation,  child: GestureDetector(  behavior: HitTestBehavior.opaque,  onTap: onTap,  child: SizedBox(  height: 80.0,  child: Card(  color: Colors.primaries[item % Colors.primaries.length],  child: Center(  child: Text('Item $item', style: textStyle),  ),  ),  ),  ),  ),  );  } }  

Ответ №1:

Таким образом, обычно невозможно (или не рекомендуется) вызывать функцию из родительского виджета, обычно все общение между родителем и ребенком выглядит следующим образом:

  --------   -------  | parent | ---data---gt; | child | | | lt;-callback- | |  --------   -------   

В вашем случае это, вероятно, означает, что оба _list и _selectedItem должны быть частью вашего родительского виджета и передаваться в качестве данных для использования дочерним виджетом.

 class AnimatedListWidget extends StatelessWidget  {  AnimatedListWidget({this.selectedItem, required this.list, required this.listKey, required this.changeSelected});   final int? selectedItem;  final ListModellt;intgt; list;  final GlobalKeylt;AnimatedListStategt; listKey;  final ValueChangedlt;intgt;? changeSelected;   @override  Widget build(BuildContext context) {  return Scaffold(  body: Padding(  padding: const EdgeInsets.all(16.0),  child: SingleChildScrollView(  child: Expanded(  child: AnimatedList(  shrinkWrap: true,  key: _listKey,  initialItemCount: list.length,  itemBuilder: _buildItem,  ),  ))));  }  Widget _buildItem(  BuildContext context, int index, Animationlt;doublegt; animation) {  return CardItem(  animation: animation,  item: list[index],  selected: selectedItem == list[index],  onTap: changeSelected==null?null : () =gt; changeSelected(index);  },  );  } }  

Затем на родительском виджете:

 class ParentWidget extends StatefulWidget {  ... }  class _ParentWidgetState extends Statelt;ParentWidgetgt; {   final GlobalKeylt;AnimatedListStategt; _listKey = GlobalKeylt;AnimatedListStategt;();  late ListModellt;intgt; _list;  int? _selectedItem;  late int  _nextItem; // The next item inserted when the user presses the ' ' button.   @override  void initState() {  super.initState();  _list = ListModellt;intgt;(  listKey: _listKey,  initialItems: lt;intgt;[0, 1, 2],  removedItemBuilder: _buildRemovedItem,  );  _nextItem = 3;  }   @override Widget build(BuildContext context) {  return AnimatedListWidget(  selectedItem = _selectedItem,  list: _list,  listKey: _listKey,  changeSelected: (i) =gt; setState(() =gt;_selectedItem = _selectedItem == _list[i] ? null : _list[i]),  );  }   void addPresetToList() {  final int index =  _selectedItem == null ? _list.length : _list.indexOf(_selectedItem!);  _list.insert(index, _nextItem  );  setState(() {});  }  }  

Таким образом, родитель может получить доступ к функции, поскольку она является частью родителя. Если вы хотите, чтобы ребенок получил к нему доступ, вы должны передать его в качестве обратного вызова, как если бы onPressed вы использовали метод на кнопке с повышенным уровнем

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

1. в нем много проблем с ошибками, одна из них ListModel не определена, и когда я определяю ее в ребенке, это дает больше бесконечных ошибок. Вы уверены, что код завершен?

2. нет, это не должно было быть полным, это был просто пример того, как это должно работать, я думаю, вы должны определить ListModel list_model.dart и импортировать его в оба файла? может быть, это решит проблему с ошибкой?