Чтобы вызвать функцию родителя, вы можете использовать шаблон обратного вызова.В этом примере функция (onColorSelected
) передается дочернему элементу.Ребенок вызывает функцию при нажатии кнопки:
import 'package:flutter/material.dart';
class Parent extends StatefulWidget {
@override
State<StatefulWidget> createState() {
return ParentState();
}
}
class ParentState extends State<Parent> {
Color selectedColor = Colors.grey;
@override
Widget build(BuildContext context) {
return Column(
children: <Widget>[
Container(
color: selectedColor,
height: 200.0,
),
ColorPicker(
onColorSelect: (Color color) {
setState(() {
selectedColor = color;
});
},
)
],
);
}
}
class ColorPicker extends StatelessWidget {
const ColorPicker({this.onColorSelect});
final ColorCallback onColorSelect;
@override
Widget build(BuildContext context) {
return Row(
children: <Widget>[
RaisedButton(
child: Text('red'),
color: Colors.red,
onPressed: () {
onColorSelect(Colors.red);
},
),
RaisedButton(
child: Text('green'),
color: Colors.green,
onPressed: () {
onColorSelect(Colors.green);
},
),
RaisedButton(
child: Text('blue'),
color: Colors.blue,
onPressed: () {
onColorSelect(Colors.blue);
},
)
],
);
}
}
typedef ColorCallback = void Function(Color color);
Внутренние виджеты Flutter, такие как кнопки или поля формы, используют точно такой же шаблон.Если вы хотите вызывать функцию только без аргументов, вы можете использовать тип VoidCallback
вместо определения своего собственного типа обратного вызова.
Если вы хотите уведомить вышестоящего родителя, вы можете просто повторитьэтот шаблон на каждом уровне иерархии:
class ColorPickerWrapper extends StatelessWidget {
const ColorPickerWrapper({this.onColorSelect});
final ColorCallback onColorSelect;
@override
Widget build(BuildContext context) {
return Padding(
padding: EdgeInsets.all(20.0),
child: ColorPicker(onColorSelect: onColorSelect),
)
}
}
В Flutter не рекомендуется вызывать метод дочернего виджета из родительского виджета.Вместо этого Flutter рекомендует передавать состояние потомка в качестве параметров конструктора.Вместо вызова метода потомка, вы просто вызываете setState
в родительском виджете, чтобы обновить его потомки.
Один альтернативный подход - классы controller
в Flutter (ScrollController
, AnimationController
, ...).Они также передаются дочерним элементам в качестве параметров конструктора и содержат методы для управления состоянием дочернего элемента без вызова setState
для родительского элемента.Пример:
scrollController.animateTo(200.0, duration: Duration(seconds: 1), curve: Curves.easeInOut);
Затем дети должны прослушать эти изменения, чтобы обновить свое внутреннее состояние.Конечно, вы также можете реализовать свой собственный класс контроллера.Если вам нужно, я рекомендую вам взглянуть на исходный код Flutter, чтобы понять, как это работает.
Фьючерсы и потоки являются еще одной альтернативой для передачи состояния и могут также использоваться для вызовафункция ребенка.
Но я действительно не рекомендую это.Если вам нужно вызвать метод дочернего виджета, очень похоже, что ваша прикладная архитектура имеет недостатки. Попробуйте переместить состояние до общего предка!