前言

最近在用flutter写一个小项目,在写主页面(底部导航栏+子页面)时遇到的一个问题:当点击底部item切换到另一页面, 再返回此页面时会重走它的initState方法(我们一般在initState中发起网络请求,或者初始化的操作),导致不必要的开销

根据Tab动态加载页面

我们先定义两个页面PageA和PageB

class PageA extends StatefulWidget {
_PageAState createState() => _PageAState();
} class _PageAState extends State<PageA> {
@override
void initState() {
super.initState();
print("pageA init state");
} @override
Widget build(BuildContext context) {
return Container(
color: Colors.orangeAccent,
child: Center(
child: Text("page A"),
),
);
}
} class PageB extends StatefulWidget {
_PageBState createState() => _PageBState();
} class _PageBState extends State<PageB> {
@override
void initState() {
super.initState();
print("pageB init state");
} @override
Widget build(BuildContext context) {
return Container(
color: Colors.blueAccent,
child: Center(
child: Text("page B"),
),
);
}
}

定义Tab主页面

import 'package:flutter/material.dart';

void main() => runApp(MyApp());

class MyApp extends StatefulWidget {
_MyAppState createState() => _MyAppState();
} class _MyAppState extends State<MyApp> {
int _tabIndex = 0; List<Widget> _tabWidget = [
PageA(),
PageB()
]; @override
Widget build(BuildContext context) {
return MaterialApp(
title: 'tab demo',
home: Scaffold(
bottomNavigationBar: BottomNavigationBar(
items: _createBottomItems(),
currentIndex: this._tabIndex,
onTap: (index) {
setState(() {
this._tabIndex = index;
});
},
),
body: this._tabWidget.elementAt(this._tabIndex),
),
);
}
} // 创建底部导航item
List<BottomNavigationBarItem> _createBottomItems() {
return [
BottomNavigationBarItem(
icon: Icon(Icons.home),
title: Text("首页")
),
BottomNavigationBarItem(
icon: Icon(Icons.insert_emoticon),
title: Text("我的")
)
];

运行后发现,每次切换tab都会调用initState,这显然不符合我们的正常的需求,有下面两种解决方式

IndexedStack

IndexedStack可以控制子元素的显示和隐藏,并且会缓存所有的元素,不会每次都重新创建子元素

  @override
Widget build(BuildContext context) {
return MaterialApp(
title: 'tab demo',
home: Scaffold(
bottomNavigationBar: BottomNavigationBar(
items: _createBottomItems(),
currentIndex: this._tabIndex,
onTap: (index) {
setState(() {
this._tabIndex = index;
});
},
),
body: IndexedStack(
children: this._tabWidget,
index: this._tabIndex,
)
),
);
}

运行后发现还是有个问题,IndexedStack在初始化的时候会初始化所有的子元素,pageA和pageB的initState会同时调用,这明显还是不符合我们的需求

正确来说应该是切换到具体页面的时候才进行初始化,而不是一开始就加载所有的页面的数据,避免资源浪费

PageView + AutomaticKeepAliveClientMixin

使用PageView支持多个view切换,并且不会一次加载完所有的页面

PageController _pageController;

   @override
void initState() {
super.initState();
this._pageController =PageController(initialPage: this._tabIndex, keepPage: true);
} @override
Widget build(BuildContext context) {
return MaterialApp(
title: 'tab demo',
home: Scaffold(
bottomNavigationBar: BottomNavigationBar(
items: _createBottomItems(),
currentIndex: this._tabIndex,
onTap: (index) {
setState(() {
this._tabIndex = index;
_pageController.jumpToPage(index);
});
},
),
body: PageView(
children: this._tabWidget,
controller: _pageController,
),
),
);
}
}

使用PageView可以正常切换,但是每次切换Tab的时候还是会重复调用initState,我们还需要在子页面实现AutomaticKeepAliveClientMixin

class _PageAState extends State<PageA> with AutomaticKeepAliveClientMixin {
@override
bool get wantKeepAlive => true; ...
}
class _PageBState extends State<PageB> with AutomaticKeepAliveClientMixin {
@override
bool get wantKeepAlive => true; ...
}

实现了AutomaticKeepAliveClientMixin就不会每次切换Tab都调用initState了,这也是google推荐的方式

最后发现PageView可以左右滑动切换,这个可以通过设置physics为NeverScrollableScrollPhysics()来禁止滑动

PageView(
children: this._tabWidget,
controller: _pageController,
physics: NeverScrollableScrollPhysics(),
)

参考来源:https://blog.bombox.org/2019-02-23/flutter-tab-keep-alive/#more

flutter 切换tab后保留tab状态的更多相关文章

  1. easyui tree 编辑后保留原先状态

    $(function () { var selected = $('#depttree').tree('getSelected'); $('#depttree').tree({ checkbox: f ...

  2. Flutter——TabBar组件(顶部Tab切换组件)

    TabBar组件的常用属性: 属性 描述 tabs 显示的标签内容,一般使用 Tab 对象,也可以是其他的Widget  controller TabController 对象 isScrollabl ...

  3. 很好用的Tab标签切换功能,延迟Tab切换。

    一个网页,Tab标签的切换是常见的功能,但我发现很少有前端工程师在做该功能的时候,会为用户多想想,如果你觉得鼠标hover到标签上,然后切换到相应的内容,就那么简单的话,你将是一个不合格的前端工程师啊 ...

  4. easyui修复浏览器刷新后,tab页全部关闭的问题

    一.问题描述 使用easyui搭建的上左右页面布局,当我们在右侧打开了tab页,发现点击浏览器的刷新按钮后,整个页面会被重新渲染,导致所有打开的tab页都被关闭,回到初始状态的问题. 这个问题虽然不影 ...

  5. 微信小程序自定义tab,多层tab嵌套实现

    小程序最近是越来越火了-- 做小程序有一段时间了,总结一下项目中遇到的问题及解决办法吧. 项目中有个多 tab 嵌套的需求,进入程序主界面下面有两个 tab,进入A模块后,A模块最底下又有多个tab, ...

  6. 在Bootstrap开发框架的工作流模块中实现流程完成后更新资料状态处理

    在开发查看流程表单明细的时候,在Web界面中,我们往往通过使用@RenderPage实现页面内容模块化的隔离,减少复杂度,因此把一些常用的如审批.撤销.会签.阅办等等的流程步骤都放到了通用处理的页面V ...

  7. 低版本系统兼容的ActionBar(四)添加Tab+添加自定义的Tab视图+Fragment

    在ActionBar中添加Tab是很有用的技巧.在support V7库的支持下,我们几乎可以用和之前一样的方式来添加Tab,对于Tab来说,我们可以和MenuItem一样,给他定义自己的视图.我这里 ...

  8. 刨根问底U3D---如何退出Play模式后保留数据更改

    实际中遇到的需求 在做一款对抗类游戏,目前正在调整游戏的平衡性 所以就产生了一个需求 希望可以在Play模式时候对数据源做的更改可以在退出时候被保存下来. 举个Case, 比如 有一个炮塔 可以发射子 ...

  9. C# 版本的 计时器类:精确到微秒 秒后保留一位小数 支持年月日时分秒带单位的输出

    class TimeCount { // 临时变量,存放当前类能表示的最大年份值 ; /// <summary> /// 获取毫秒能表示的最大年份数 /// </summary> ...

随机推荐

  1. linux 重定向类型 超级块 i节点

    超级块:定义文件系统的元数据(总大小.块大小.空闲.......):在格式化的时候确定 查看超级块信息:tune2fs  -l   目录 i节点:定义文件的元数据(名称.大小.存放位置.权限.修改时间 ...

  2. linux基础—课堂随笔09_数组

    数组:(6.14 第一节) 取分区利用率,大于百分之八十则发出警报 取分区第一列 取分区使用率: 脚本: 检查脚本语法: ——end 数组切片: 1.跳过前两个取后面 2.跳过前两个取三个 生成10个 ...

  3. Ubuntu18.04安装 NVIDIA驱动

    Ubuntu18.04安装 NVIDIA驱动 参考自博客:https://blog.csdn.net/jsjason1/article/details/88086904 我确定这篇文章是否很有必要,我 ...

  4. tensorflow2.0 在pycharm下提示问题

    tensorflow2.0 使用keras一般通过tensorflow.keras来使用,但是pycharm没有提示,原因是因为实际的keras路径放在tensorflow/python/keras, ...

  5. pycharm中报错:ImportError: No module named 'skimage'

    pycharm中直接setting是没办法成功的,会提示is requied C++ bool.....先进入那个页面安装好需要的tools,这个安装比较慢:http://landinghub.vis ...

  6. MySQL BinLog Server 搭建实战

    一.MySQL Binlog server 介绍 MySQL Binlog Server: 它使用 mysqlbinlog 命令以 daemon 进程的方式模拟一个 slave 的 IO 线程与主库连 ...

  7. Java-Dom4jHelper工具类

    import java.io.ByteArrayOutputStream; import java.io.File; import java.io.FileInputStream; import ja ...

  8. mysql的五大引擎跟优劣之分

    MySQL有多种存储引擎,每种存储引擎有各自的优缺点,可以择优选择使用: MERGE.MEMORY(HEAP).EXAMPLE.ARCHIVE.CSV. · MEMORY存储引擎提供“内存中”表.ME ...

  9. P1121 环状最大两段子段和(DP)

    P1121 环状最大两段子段和 难度 提高+/省选- 题目描述 给出一段环状序列,即认为A[1]和A[N]是相邻的,选出其中连续不重叠且非空的两段使得这两段和最大. 输入输出格式 输入格式: 输入文件 ...

  10. axios的post传参时,将参数转为form表单格式

    import axios from 'axios'; import alert from './alert.js'; import Qs from 'qs' //引入qs 时axios的自带模块 le ...