最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

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

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

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

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, 關(guān)閉頁面時就會導(dǎo)致后面的頁面被再次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) {
    //頁面已經(jīng)選中
    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);
    });
  }
  //關(guān)閉頁面
  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("初始化頁面內(nèi)容控制器:${widget.data}");
    setState(() {
      for (int index = 0; index <= 30; index++) {
        listItems.add("${widget.data} - $index");
      }
    });
    super.initState();
  }
  @override
  void dispose() {
    print("釋放頁面內(nèi)容控制器:${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))
        ],
      ),
    );
  }
}

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

相關(guān)文章

  • 詳解關(guān)于mybatis-plus中Service和Mapper的分析

    詳解關(guān)于mybatis-plus中Service和Mapper的分析

    這篇文章主要介紹了詳解關(guān)于mybatis-plus中Service和Mapper的分析,文中通過示例代碼介紹的非常詳細,對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2020-09-09
  • SpringSecurity實現(xiàn)原理及多過濾器鏈匹配規(guī)則詳解

    SpringSecurity實現(xiàn)原理及多過濾器鏈匹配規(guī)則詳解

    SpringSecurity通過FilterChainProxy管理多個過濾器鏈,根據(jù)請求的URI和RequestMatcher匹配,選擇合適的過濾器鏈進行認證和授權(quán)處理,配置多個過濾器鏈需用@Order區(qū)分優(yōu)先級,處理流程清晰高效
    2025-10-10
  • SpringBoot之如何搭建SpringBoot+Maven項目

    SpringBoot之如何搭建SpringBoot+Maven項目

    這篇文章主要介紹了SpringBoot之如何搭建SpringBoot+Maven項目問題,具有很好的參考價值,希望對大家有所幫助,如有錯誤或未考慮完全的地方,望不吝賜教
    2024-07-07
  • Delegate IDE build/run actions to maven 配置會影響程序運行嗎?

    Delegate IDE build/run actions to maven 配置會影響程序運行嗎?

    這篇文章主要介紹了Delegate IDE build/run actions to maven 配置會影響程序運行嗎,本文給大家介紹的非常詳細,對大家的學(xué)習(xí)或工作具有一定的參考借鑒價值,需要的朋友可以參考下
    2020-08-08
  • Springboot如何解決前端請求跨域的問題

    Springboot如何解決前端請求跨域的問題

    這篇文章主要介紹了Springboot如何解決前端請求跨域的問題,具有很好的參考價值,希望對大家有所幫助,如有錯誤或未考慮完全的地方,望不吝賜教
    2024-07-07
  • Java網(wǎng)約車項目實戰(zhàn)之實現(xiàn)搶單功能詳解

    Java網(wǎng)約車項目實戰(zhàn)之實現(xiàn)搶單功能詳解

    本文詳細介紹了如何使用Java實現(xiàn)網(wǎng)約車項目的搶單功能,并提供了一個完整的代碼示例,以便讀者能夠直接運行和參考,感興趣的朋友一起看看吧
    2024-12-12
  • 解決因缺少Log4j依賴導(dǎo)致應(yīng)用啟動失敗的問題

    解決因缺少Log4j依賴導(dǎo)致應(yīng)用啟動失敗的問題

    日志是應(yīng)用軟件中不可缺少的部分,Apache的開源項目log4j是一個功能強大的日志組件,提供方便的日志記錄。但這篇文章不是介紹Log4j,這篇文章主要介紹了關(guān)于因缺少Log4j依賴導(dǎo)致應(yīng)用啟動失敗問題的相關(guān)資料,需要的朋友可以參考下。
    2017-04-04
  • SpringBoot Mybatis 配置文件形式詳解

    SpringBoot Mybatis 配置文件形式詳解

    這篇文章主要介紹了SpringBoot Mybatis 配置文件形式詳解,本文給大家介紹的非常詳細,對大家的學(xué)習(xí)或工作具有一定的參考借鑒價值,需要的朋友可以參考下
    2023-03-03
  • Java線程創(chuàng)建(賣票),線程同步(賣包子)的實現(xiàn)示例

    Java線程創(chuàng)建(賣票),線程同步(賣包子)的實現(xiàn)示例

    這篇文章主要介紹了Java線程創(chuàng)建(賣票),線程同步(賣包子)的實現(xiàn)示例,文中通過示例代碼介紹的非常詳細,對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2021-05-05
  • Java設(shè)計模式之裝飾模式詳解

    Java設(shè)計模式之裝飾模式詳解

    這篇文章主要介紹了Java設(shè)計模式中的裝飾者模式,裝飾者模式即Decorator Pattern,裝飾模式是在不必改變原類文件和使用繼承的情況下,動態(tài)地擴展一個對象的功能,裝飾模式又名包裝模式。裝飾器模式以對客戶端透明的方式拓展對象的功能,是繼承關(guān)系的一種替代方案
    2022-08-08

最新評論

陇川县| 河西区| 大渡口区| 万安县| 罗甸县| 商水县| 改则县| 澄迈县| 乌拉特中旗| 吉隆县| 多伦县| 蒙山县| 泾源县| 平湖市| 古丈县| 阳城县| 奉新县| 竹山县| 民乐县| 都兰县| 安国市| 常州市| 利津县| 孟津县| 苍溪县| 昂仁县| 富平县| 特克斯县| 沙湾县| 修文县| 廉江市| 宜阳县| 武陟县| 玉林市| 壶关县| 湘西| 兴文县| 灵宝市| 拜泉县| 三台县| 北辰区|