- 文档:
- https://flutter.cn">1. Flutter中文网: https://flutter.cn
- 转化:
- https://tnfe.github.io/c2f/">1. CSS转Flutter: https://tnfe.github.io/c2f/
- https://app.quicktype.io/">2. json转实体类: https://app.quicktype.io/
- 哇🤩:
文档:
1. Flutter中文网: https://flutter.cn
转化:
1. CSS转Flutter: https://tnfe.github.io/c2f/
2. json转实体类: https://app.quicktype.io/
哇🤩:
1.去除点击水波纹效果
MaterialApp(theme: ThemeData(primaryColor: Colors.white,brightness: Brightness.light,splashColor: Colors.transparent,highlightColor: Colors.transparent,))
Theme(data: ThemeData(brightness: Brightness.light,splashColor: Colors.transparent,highlightColor: Colors.transparent,),child: child,)
2. 顶部导航颜色与系统颜色相同(在main.dart中初始化)
void _initOverlayStyle() {if (Platform.isAndroid) {SystemUiOverlayStyle systemUiOverlayStyle = SystemUiOverlayStyle(statusBarColor: Colors.transparent,statusBarBrightness: Brightness.light,);SystemChrome.setSystemUIOverlayStyle(systemUiOverlayStyle);}}
3.切换状态时保存页面状态
:::warning ① 使用 IndexedStackIndexedStack继承自Stack,它的作用是显示第index个child,其它child在页面上是不可见的,但所有child的状态都被保持,所以这个Widget可以实现我们的需求,我们只需要将现在的body用IndexedStack包裹一层即可 :::
class _MyHomePageState extends State<MyHomePage> {.........@overrideWidget build(BuildContext context) {return Scaffold(appBar: AppBar(title: Text('demo'),),bottomNavigationBar: BottomNavigationBar(items: items, currentIndex: currentIndex, onTap: onTap),body: IndexedStack(index: currentIndex,children: bodyList,));}
:::warning
② 使用_Offstage_实现Offstage的作用十分简单,通过一个参数来控制child是否显示,所以我们同样可以组合使用Offstage来实现该需求,其实现原理与IndexedStack类似
:::
class _MyHomePageState extends State<MyHomePage> {.........@overrideWidget build(BuildContext context) {return Scaffold(appBar: AppBar(title: Text('demo'),),bottomNavigationBar: BottomNavigationBar(items: items, currentIndex: currentIndex, onTap: onTap),body: Stack(children: [Offstage(offstage: currentIndex != 0,child: bodyList[0],),Offstage(offstage: currentIndex != 1,child: bodyList[1],),Offstage(offstage: currentIndex != 2,child: bodyList[2],),],));}}
:::danger
在上面的两种方式中都可以实现保持原页面状态的需求,但这里有一些开销上的问题,当应用第一次加载的时候,所有子页状态都被实例化了(>这里的细节并不是因为我直接把子页实例化放在bodyList里…<),如果在子页State的initState中打印日志,可以在终端看到一次性输出了所有子页的日志。
:::
:::warning
③ 首先我们通过配合使用TabBar+TabBarView+AutomaticKeepAliveClientMixin来实现顶部导航(注意:TabBar和TabBarView需要提供controller,如果自己没有定义,则必须使用DefaultTabController包裹)。此处也可以选择使用PageView。
:::
import 'package:flutter/material.dart';import 'package:myflutter/page/home/Home.dart';class BottomNavigationWidget extends StatefulWidget {@overrideState<StatefulWidget> createState() => BottomNavigationWidgetState();}class BottomNavigationWidgetState extends State<BottomNavigationWidget> {int _currentIndex = 0;PageController _pageController;@overridevoid initState() {super.initState();this._pageController = PageController(initialPage: this._currentIndex);}List<Widget> pages = [ HomePage() ];@overrideWidget build(BuildContext context) {return Scaffold(body: PageView(physics: NeverScrollableScrollPhysics(), // 禁用左右滑动controller: this._pageController,children: this.pages,),bottomNavigationBar: BottomNavigationBar(items: [BottomNavigationBarItem(icon: Icon(Icons.live_tv,),title: Text('直播',),),],currentIndex: this._currentIndex,onTap: (int index) {setState(() {this._currentIndex = index;this._pageController.jumpToPage(this._currentIndex);});},fixedColor: Color.fromRGBO(234, 214, 77, 1.0),type: BottomNavigationBarType.fixed,),);}}
:::warning
在需要保存状态的页面内添加
with AutomaticKeepAliveClientMixin
并且实现
@override
bool get wantKeepAlive => true;
:::
class _HomePageState extends State<HomePage>with AutomaticKeepAliveClientMixin {@overridebool get wantKeepAlive => true;}
:::warning
可能有些小伙伴在搜索后会开始直接使用官方推荐的AutomaticKeepAliveClientMixin,通过在子页面的State类重写wantKeepAlive为true 。 然而,如果你的代码和我上面的类似,body中并没有使用PageView或TabBarView,很不幸的告诉你,踩到坑了,这样是无效的
:::
:::info TabBarView+AutomaticKeepAliveClientMixin,3 个页面(A,B,C),从 C 页面直接切换到 A 页面时,B 页面会重新initState,而且已加载的数据(如数组),会丢失。 :::
在所有使用了AutomaticKeepAliveClientMixin父页面的build方法最上边调用 super.build(context);就可以了.@overrideWidget build(BuildContext context) {super.build(context);}
4.禁止左右滑动切换
PageView( physics: NeverScrollableScrollPhysics(), // 禁用左右滑动 )
5.ListView, GridView中, 是否根据子组件的总长度来设置ListView的长度,默认值为false 。默认情况下,ListView的会在滚动方向尽可能多的占用空间。当ListView在一个无边界(滚动方向上)的容器中时,shrinkWrap必须为true。
shrinkWrap: true

