欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

flutter?TabBarView?動態(tài)添加刪除頁面的示例代碼

 更新時間:2024年11月18日 09:49:32   作者:愛學習的綠葉  
在Flutter中使用TabBarView動態(tài)添加和刪除頁面時,如果未為每個頁面設置唯一的key,會導致刪除頁面時出現(xiàn)狀態(tài)錯誤或刪除錯誤的頁面,正確的做法是為每個頁面指定全局唯一的key,這樣可以確保頁面在添加和刪除時狀態(tài)正確,感興趣的朋友跟隨小編一起看看吧

在TabBarView 動態(tài)添加頁面后刪除其中一個頁面會導致后面的頁面狀態(tài)錯誤或刪除的頁面不正確。出現(xiàn)這種問題是由于創(chuàng)建子頁面時沒有為子頁面設置唯一的key導致的。下面是錯誤的代碼:

void addNewPage() {
    _pageCount++;
    setState(() {
      String title = "頁面$_pageCount";
      PageContent page = PageContent(data: title, pageId: _pageCount,);
      PageData data = PageData(data: title, pageId: _pageCount, content: page);
      listPages.add(data);
      nowIndex = listPages.length -1;
      resetTabController();
    });
  }

如上面的代碼所示, 在創(chuàng)建PageContent 組件時如果沒有指定全局唯一的key, 關閉頁面時就會導致后面的頁面被再次build或刪除錯誤的頁面,正確的代碼如下

void addNewPage() {
    _pageCount++;
    setState(() {
      String title = "頁面$_pageCount";
      PageContent page = PageContent(data: title, pageId: _pageCount, key: ValueKey(title),);
      PageData data = PageData(data: title, pageId: _pageCount, content: page);
      listPages.add(data);
      nowIndex = listPages.length -1;
      resetTabController();
    });
  }

指定了全局唯一key后在刪除子頁面,后續(xù)頁面就可以正常顯示。

所有代碼如下

import 'package:flutter/material.dart';
void main() {
  runApp(const MainApp());
}
class MainApp extends StatelessWidget {
  const MainApp({super.key});
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      theme: ThemeData(
        colorScheme: ColorScheme.fromSeed(seedColor: Colors.white),
        primaryColor: Colors.white,
        scaffoldBackgroundColor: Colors.white,
        dialogBackgroundColor: Colors.white,
        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: listPages.length, vsync: this);
    });
  }
  @override
  bool get wantKeepAlive => true;
  void addNewPage() {
    _pageCount++;
    setState(() {
      String title = "頁面$_pageCount";
      PageContent page = PageContent(data: title, pageId: _pageCount, key: ValueKey(title),);
      PageData data = PageData(data: title, pageId: _pageCount, content: page);
      listPages.add(data);
      nowIndex = listPages.length -1;
      resetTabController();
    });
  }
  //選中某個頁面
  void onSelectPage(PageData page) {
    //頁面已經選中
    int selIndex = 0;
    for (int index = 0; index < listPages.length; index++) {
      PageData item = listPages[index];
      if (item.pageId == page.pageId) {
        selIndex = index;
        break;
      }
    }
    //選中頁面沒有更改
    if (selIndex == nowIndex) {
      return;
    }
    setState(() {
      nowIndex = selIndex;
      tabController?.animateTo(nowIndex);
    });
  }
  //關閉頁面
  void onClosePage(PageData data) {
    int closedIndex = 0;
    for (int index = 0; index < listPages.length; index++) {
      PageData item = listPages[index];
      if (item.pageId == data.pageId) {
        closedIndex = index;
        break;
      }
    }
    setState(() {
      listPages.removeAt(closedIndex);
      if (closedIndex <= nowIndex) {
        nowIndex--;
      }
      if (nowIndex < 0) {
        nowIndex = 0;
      } else if (nowIndex >= listPages.length) {
        nowIndex = listPages.length -1;
      }
      resetTabController();
    });
  }
  void resetTabController() {
    if (tabController?.length != listPages.length) {
      tabController?.dispose();
      tabController = TabController(
        length: listPages.length,
        vsync: this,
        initialIndex: nowIndex,
      );
    }
  }
  @override
  Widget build(BuildContext context) {
    super.build(context);
    return Scaffold(
      appBar: AppBar(
        bottom: PreferredSize(
            preferredSize: const Size.fromHeight(40),
            child: TabBar(
                controller: tabController,
                tabs: listPages.map((item) => Tab(child: TitleBarItem(data: item, closeCallback: (data) => onClosePage(data)),)).toList(),
            ),
        ),
      ),
      body: TabBarView(
        controller: tabController,
        children: listPages.map((item) => item.content).toList(),
      ),
      floatingActionButton: FloatingActionButton(
        onPressed: () => addNewPage(),
        tooltip: 'Increment',
        child: const Icon(Icons.add),
      ),
    );
  }
}
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("初始化頁面內容控制器:${widget.data}");
    setState(() {
      for (int index = 0; index <= 30; index++) {
        listItems.add("${widget.data} - $index");
      }
    });
    super.initState();
  }
  @override
  void dispose() {
    print("釋放頁面內容控制器:${widget.data}");
    super.dispose();
  }
  @override
  bool get wantKeepAlive => true;
  @override
  Widget build(BuildContext context) {
    print("Build頁面 ${widget.data}");
    return Container(
      alignment: Alignment.center,
      child: Column(
        children: [
          Text(widget.data),
          Expanded(
            child: ListView.builder(
                itemExtent: 30,
                itemCount: listItems.length,
                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(data.data)),
          IconButton(
              onPressed: () => closeCallback(data),
              icon: const Icon(Icons.close))
        ],
      ),
    );
  }
}

到此這篇關于flutter TabBarView 動態(tài)添加刪除頁面的文章就介紹到這了,更多相關flutter TabBarView 刪除頁面內容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關文章希望大家以后多多支持腳本之家!

相關文章

  • SpringBoot異步調用相同類的解決方案

    SpringBoot異步調用相同類的解決方案

    在SpringBoot中,同一個類中調用帶有@Async注解的方法時,異步調用會失效,因為直接通過this調用方法時,并沒有通過Spring的代理對象,下面給大家分享SpringBoot異步調用相同類的解決方案,感興趣的朋友一起看看吧
    2025-02-02
  • SpringBoot創(chuàng)建監(jiān)聽器的方法示例

    SpringBoot創(chuàng)建監(jiān)聽器的方法示例

    在Java中,監(jiān)聽器(Listener)是一種設計模式,它允許對象在 特定事件 發(fā)生時 自動執(zhí)行某些操作,這種設計模式通常用于實現(xiàn) 發(fā)布-訂閱模型,本文給大家介紹了SpringBoot創(chuàng)建監(jiān)聽器的方法示例,感興趣的通過可以參考一下
    2024-04-04
  • Java?抽象類和接口的實現(xiàn)

    Java?抽象類和接口的實現(xiàn)

    本文主要介紹了Java?抽象類和接口,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧
    2007-03-03
  • java 設計模式之State(狀態(tài)模式)

    java 設計模式之State(狀態(tài)模式)

    這篇文章主要介紹了java 設計模式之State(狀態(tài)模式)的相關資料,一個類的行為基于它的狀態(tài)的改變而改變。狀態(tài)模式歸屬于行為型模式,需要的朋友可以參考下
    2017-08-08
  • java垃圾回收原理之GC算法基礎

    java垃圾回收原理之GC算法基礎

    本章簡要介紹GC的基本原理和相關技術, 下一章節(jié)再詳細講解GC算法的具體實現(xiàn)。各種垃圾收集器的實現(xiàn)細節(jié)雖然并不相同,但總體而言,垃圾收集器都專注于兩件事情:查找所有存活對象,拋棄其他的部分,即死對象,不再使用的對象
    2022-01-01
  • java 實現(xiàn)DES 加密解密的示例

    java 實現(xiàn)DES 加密解密的示例

    這篇文章主要介紹了java 實現(xiàn)DES 加密解密的示例代碼,幫助大家更好的理解和使用Java進行加解密,感興趣的朋友可以了解下
    2020-12-12
  • java開源好用的簡繁轉換類庫推薦

    java開源好用的簡繁轉換類庫推薦

    這篇文章主要為大家介紹了java開源好用的簡繁轉換類庫推薦,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪
    2022-08-08
  • Spring中的@PropertySource注解源碼詳細解析

    Spring中的@PropertySource注解源碼詳細解析

    這篇文章主要介紹了Spring中的@PropertySource注解源碼詳細解析,@PropertySource注解,標注在配置類@Configuration上面,下面主要分析一下@PropertySource注解的處理過程,也就是怎么把配置信息從.properies文件放到environment中的,需要的朋友可以參考下
    2024-01-01
  • SpringBoot讀取Resource目錄下文件的四種方式總結

    SpringBoot讀取Resource目錄下文件的四種方式總結

    在Spring?Boot項目中,經常需要獲取resources目錄下的文件,這些文件可以包括配置文件、模板文件、靜態(tài)資源等,本文將介紹四種常用的方法來獲取resources目錄下的文件,需要的朋友可以參考下
    2023-08-08
  • mybatisPlus實現(xiàn)倒序拼接字符串

    mybatisPlus實現(xiàn)倒序拼接字符串

    這篇文章主要介紹了mybatisPlus實現(xiàn)倒序拼接字符串方式,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教
    2022-01-01

最新評論