import 'package:flutter/';
void main() {
runApp(const MainApp());
}
class MainApp extends StatelessWidget {
const MainApp({super.key});
@override
Widget build(BuildContext context) {
return MaterialApp(
theme: ThemeData(
colorScheme: (seedColor: ),
primaryColor: ,
scaffoldBackgroundColor: ,
dialogBackgroundColor: ,
useMaterial3: true,
),
home: const PageMain(),
/*
home: ChangeNotifierProvider(
create: (context) => HomeProvider(),
builder: (context, child) => const HomePage(),
),
*/
);
}
}
class PageData {
final String data;
final int pageId;
final Widget content;
PageData({
required this.data,
required this.pageId,
required this.content,
});
}
class _StatePageMain extends State<PageMain> with TickerProviderStateMixin, AutomaticKeepAliveClientMixin {
final List<PageData> listPages = <PageData>[];
int nowIndex = 0;
int _pageCount = 0;
TabController? tabController;
@override
void initState() {
super.initState();
setState(() {
tabController = TabController(length: , vsync: this);
});
}
@override
bool get wantKeepAlive => true;
void addNewPage() {
_pageCount++;
setState(() {
String title = "page $_pageCount";
PageContent page = PageContent(data: title, pageId: _pageCount, key: ValueKey(title),);
PageData data = PageData(data: title, pageId: _pageCount, content: page);
(data);
nowIndex = -1;
resetTabController();
});
}
//Select a page
void onSelectPage(PageData page) {
//The page has been selected
int selIndex = 0;
for (int index = 0; index < ; index++) {
PageData item = listPages[index];
if ( == ) {
selIndex = index;
break;
}
}
//No changes to selected pages
if (selIndex == nowIndex) {
return;
}
setState(() {
nowIndex = selIndex;
tabController?.animateTo(nowIndex);
});
}
//close page
void onClosePage(PageData data) {
int closedIndex = 0;
for (int index = 0; index < ; index++) {
PageData item = listPages[index];
if ( == ) {
closedIndex = index;
break;
}
}
setState(() {
(closedIndex);
if (closedIndex <= nowIndex) {
nowIndex--;
}
if (nowIndex < 0) {
nowIndex = 0;
} else if (nowIndex >= ) {
nowIndex = -1;
}
resetTabController();
});
}
void resetTabController() {
if (tabController?.length != ) {
tabController?.dispose();
tabController = TabController(
length: ,
vsync: this,
initialIndex: nowIndex,
);
}
}
@override
Widget build(BuildContext context) {
super.build(context);
return Scaffold(
appBar: AppBar(
bottom: PreferredSize(
preferredSize: const (40),
child: TabBar(
controller: tabController,
tabs: ((item) => Tab(child: TitleBarItem(data: item, closeCallback: (data) => onClosePage(data)),)).toList(),
),
),
),
body: TabBarView(
controller: tabController,
children: ((item) => ).toList(),
),
floatingActionButton: FloatingActionButton(
onPressed: () => addNewPage(),
tooltip: 'Increment',
child: const Icon(),
),
);
}
}
class PageMain extends StatefulWidget {
const PageMain({super.key});
@override
State<PageMain> createState() => _StatePageMain();
}
class _StatePageContent extends State<PageContent> with AutomaticKeepAliveClientMixin {
List<String> listItems = <String>[];
@override
void initState() {
print("Initialize page content controller:${}");
setState(() {
for (int index = 0; index <= 30; index++) {
("${} - $index");
}
});
super.initState();
}
@override
void dispose() {
print("Release page content controller:${}");
super.dispose();
}
@override
bool get wantKeepAlive => true;
@override
Widget build(BuildContext context) {
print("Build page ${}");
return Container(
alignment: ,
child: Column(
children: [
Text(),
Expanded(
child: (
itemExtent: 30,
itemCount: ,
itemBuilder: (context, index) {
return Text(listItems[index]);
}
),
),
],
),
);
}
}
class PageContent extends StatefulWidget {
final int pageId;
final String data;
const PageContent({super.key, required this.data, required this.pageId});
@override
State<PageContent> createState() {
return _StatePageContent();
}
}
typedef ClickCallback = void Function(PageData data);
class TitleBarItem extends StatelessWidget {
final PageData data;
final ClickCallback closeCallback;
const TitleBarItem({
super.key,
required this.data,
required this.closeCallback,
});
@override
Widget build(BuildContext context) {
return SizedBox(
width: 200,
child: Row(
children: [
Expanded(child: Text()),
IconButton(
onPressed: () => closeCallback(data),
icon: const Icon())
],
),
);
}
}