#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
и импортировать его в оба файла? может быть, это решит проблему с ошибкой?