#flutter #dart
#flutter #dart
Вопрос:
У меня есть defaultTabController, который отображает вкладки и TabBarView на основе списка TabItem (title, widget), где заголовок соответствует заголовку на вкладке, а widget — виджет с отслеживанием состояния для отображения в TabBarView.
Всякий раз, когда я widgetList.add() добавляю новый TabItem в этот список TabItem, вызываются initState() и dispose() этого виджета с отслеживанием состояния. Но когда я widgetList.insert, это не так.
Просто любопытно, почему это происходит только тогда, когда оно добавляется в конец списка.
Вот панель управления, которая показывает это. Просто прокомментируйте и раскомментируйте соответствующим образом при опробовании widgetList.add и widgetList.insert: https://dartpad.dev/?id=d84d7236a50c0c4769427fcc8b287f41amp;null_safety=true
Спасибо!
Ответ №1:
Я наблюдал, рассматривая разные сценарии.
- widgetList пуст и использует add
List<TabItem> widgetList = [];
..
// added this count to check which widget is calling init or dispose
widgetList.add(TabItem("Added", AWidget(count: count)));
- Начальный: нет виджета
- Первое нажатие: добавляет виджет (печатает init 0)
- Второе нажатие: добавляет другой виджет (печатает init1 dispose1)
- Дальнейшие нажатия: ничего не печатается
- Список виджетов, содержащий 3 вкладки и использующий add
List<TabItem> widgetList = [];
..
// added this count to check which widget is calling init or dispose
List<TabItem> widgetList = [
TabItem("Test", const AWidget(count: 0)),
TabItem("Test", const AWidget(count: 1)),
TabItem("Test", const AWidget(count: 2))
];
- Начальный: содержит 2 вкладки (выводит init0)
- Дальнейшие нажатия: ничего не печатается
- widgetList пуст и использует insert
List<TabItem> widgetList = [];
..
// added this count to check which widget is calling init or dispose
widgetList.insert(count, TabItem("Added", AWidget(count: count)));
- Начальный: нет виджета
- Первое нажатие: добавляет виджет (печатает init 0)
- Второе нажатие: добавляет другой виджет (печатает init1 dispose1)
- Дальнейшие нажатия: ничего не печатается
- Список виджетов, содержащий 3 вкладки и использующий insert
List<TabItem> widgetList = [
TabItem("Test", const AWidget(count: 0)),
TabItem("Test", const AWidget(count: 1)),
TabItem("Test", const AWidget(count: 2))
];
..
// added this count to check which widget is calling init or dispose
widgetList.insert(count, TabItem("Added", AWidget(count: count)));
- Начальный: содержит 2 вкладки (выводит init0)
- Дальнейшие нажатия: ничего не печатается
Учитывая все 4 случая: вы получаете init
и dispose
только один раз, т.е. Когда присутствует только 1 вкладка, и вы добавляете 2-ю вкладку. Это потому, что добавленная вкладка инициализируется при добавлении в TabBar
и немедленно удаляется.
Я предполагаю, что панель вкладок инициализирует (предполагаемую) функциональность при добавлении 2-й вкладки, а затем работает нормально, когда добавляются остальные.
Обычно список из двух или более виджетов вкладок.
Мое предположение было основано на этом утверждении отсюда.
Что я могу с уверенностью сказать, так это то, что такое поведение вызвано, TabBar
а не List
.
add
и insert
работает аналогично и никак не влияет на это поведение.
Между тем, когда вы переходите на другие вкладки, скажем, с 0-> 1. Затем он печатает, init1
, dispose0
. Это потому, что при удалении от виджета он инициализирует новый виджет и удаляет ранее использованный (точно так же, как действие навигации).
Я также хочу указать еще на одну вещь. Рассмотрите возможность использования add
вместо insert
, если это не требуется из-за сложности времени.
Полный код, который я использовал для тестирования (включая количество):
import 'package:flutter/material.dart';
class TabItem {
final String title;
final Widget widget;
TabItem(this.title, this.widget);
}
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
debugShowCheckedModeBanner: false,
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: const MyHomePage(),
);
}
}
class MyHomePage extends StatefulWidget {
const MyHomePage({
Key? key,
}) : super(key: key);
@override
_MyHomePageState createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
List<TabItem> widgetList = [];
int _count = 0; // use 3 when using below commented code
// List<TabItem> widgetList = [
// TabItem("Test", const AWidget(count: 0)),
// TabItem("Test", const AWidget(count: 1)),
// TabItem("Test", const AWidget(count: 2))
// ];
void _incrementCounter(int count) {
setState(() {
widgetList.add(TabItem("Added", AWidget(count: count)));
// widgetList.insert(count, TabItem("Added", AWidget(count: count)));
});
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text('Main Page'),
),
body: DefaultTabController(
length: widgetList.length,
child: Builder(
builder: (BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text("Press floating button to add to list"),
bottom: TabBar(
isScrollable: true,
tabs: <Tab>[
for (var i in widgetList)
Tab(
text: i.title,
)
],
),
),
body: TabBarView(
children: [for (var i in widgetList) i.widget]),
);
},
),
),
floatingActionButton: FloatingActionButton(
onPressed: () {
_incrementCounter(_count );
},
tooltip: 'Increment',
child: const Icon(Icons.add),
),
);
}
}
class AWidget extends StatefulWidget {
const AWidget({
Key? key,
this.count=0,
}) : super(key: key);
final int count;
@override
_AWidgetState createState() => _AWidgetState();
}
class _AWidgetState extends State<AWidget> {
@override
void initState() {
super.initState();
print('initState ${widget.count}');
}
@override
void dispose() {
print('dispose ${widget.count}');
super.dispose();
}
@override
Widget build(BuildContext context) {
return Text('something ${widget.count}');
}
}