文档:

1. Flutter中文网: https://flutter.cn

转化:

1. CSS转Flutter: https://tnfe.github.io/c2f/

2. json转实体类: https://app.quicktype.io/

哇🤩:

1.去除点击水波纹效果

  1. MaterialApp(
  2. theme: ThemeData(
  3. primaryColor: Colors.white,
  4. brightness: Brightness.light,
  5. splashColor: Colors.transparent,
  6. highlightColor: Colors.transparent,
  7. )
  8. )
  1. Theme(
  2. data: ThemeData(
  3. brightness: Brightness.light,
  4. splashColor: Colors.transparent,
  5. highlightColor: Colors.transparent,
  6. ),
  7. child: child,

2. 顶部导航颜色与系统颜色相同(在main.dart中初始化)

  1. void _initOverlayStyle() {
  2. if (Platform.isAndroid) {
  3. SystemUiOverlayStyle systemUiOverlayStyle = SystemUiOverlayStyle(
  4. statusBarColor: Colors.transparent,
  5. statusBarBrightness: Brightness.light,
  6. );
  7. SystemChrome.setSystemUIOverlayStyle(systemUiOverlayStyle);
  8. }
  9. }

3.切换状态时保存页面状态

:::warning 使用 IndexedStackIndexedStack继承自Stack,它的作用是显示第index个child,其它child在页面上是不可见的,但所有child的状态都被保持,所以这个Widget可以实现我们的需求,我们只需要将现在的body用IndexedStack包裹一层即可 :::

  1. class _MyHomePageState extends State<MyHomePage> {
  2. ...
  3. ...
  4. ...
  5. @override
  6. Widget build(BuildContext context) {
  7. return Scaffold(
  8. appBar: AppBar(
  9. title: Text('demo'),
  10. ),
  11. bottomNavigationBar: BottomNavigationBar(
  12. items: items, currentIndex: currentIndex, onTap: onTap),
  13. body: IndexedStack(
  14. index: currentIndex,
  15. children: bodyList,
  16. ));
  17. }

:::warning ② 使用_Offstage_实现
Offstage的作用十分简单,通过一个参数来控制child是否显示,所以我们同样可以组合使用Offstage来实现该需求,其实现原理与IndexedStack类似 :::

  1. class _MyHomePageState extends State<MyHomePage> {
  2. ...
  3. ...
  4. ...
  5. @override
  6. Widget build(BuildContext context) {
  7. return Scaffold(
  8. appBar: AppBar(
  9. title: Text('demo'),
  10. ),
  11. bottomNavigationBar: BottomNavigationBar(
  12. items: items, currentIndex: currentIndex, onTap: onTap),
  13. body: Stack(
  14. children: [
  15. Offstage(
  16. offstage: currentIndex != 0,
  17. child: bodyList[0],
  18. ),
  19. Offstage(
  20. offstage: currentIndex != 1,
  21. child: bodyList[1],
  22. ),
  23. Offstage(
  24. offstage: currentIndex != 2,
  25. child: bodyList[2],
  26. ),
  27. ],
  28. ));
  29. }
  30. }

:::danger 在上面的两种方式中都可以实现保持原页面状态的需求,但这里有一些开销上的问题,当应用第一次加载的时候,所有子页状态都被实例化了(>这里的细节并不是因为我直接把子页实例化放在bodyList里…<),如果在子页StateinitState中打印日志,可以在终端看到一次性输出了所有子页的日志。 :::

:::warning 首先我们通过配合使用TabBar+TabBarView+AutomaticKeepAliveClientMixin来实现顶部导航(注意:TabBarTabBarView需要提供controller,如果自己没有定义,则必须使用DefaultTabController包裹)。此处也可以选择使用PageView。 :::

  1. import 'package:flutter/material.dart';
  2. import 'package:myflutter/page/home/Home.dart';
  3. class BottomNavigationWidget extends StatefulWidget {
  4. @override
  5. State<StatefulWidget> createState() => BottomNavigationWidgetState();
  6. }
  7. class BottomNavigationWidgetState extends State<BottomNavigationWidget> {
  8. int _currentIndex = 0;
  9. PageController _pageController;
  10. @override
  11. void initState() {
  12. super.initState();
  13. this._pageController = PageController(initialPage: this._currentIndex);
  14. }
  15. List<Widget> pages = [ HomePage() ];
  16. @override
  17. Widget build(BuildContext context) {
  18. return Scaffold(
  19. body: PageView(
  20. physics: NeverScrollableScrollPhysics(), // 禁用左右滑动
  21. controller: this._pageController,
  22. children: this.pages,
  23. ),
  24. bottomNavigationBar: BottomNavigationBar(
  25. items: [
  26. BottomNavigationBarItem(
  27. icon: Icon(
  28. Icons.live_tv,
  29. ),
  30. title: Text(
  31. '直播',
  32. ),
  33. ),
  34. ],
  35. currentIndex: this._currentIndex,
  36. onTap: (int index) {
  37. setState(() {
  38. this._currentIndex = index;
  39. this._pageController.jumpToPage(this._currentIndex);
  40. });
  41. },
  42. fixedColor: Color.fromRGBO(234, 214, 77, 1.0),
  43. type: BottomNavigationBarType.fixed,
  44. ),
  45. );
  46. }
  47. }

:::warning 在需要保存状态的页面内添加
with AutomaticKeepAliveClientMixin
并且实现

@override
bool get wantKeepAlive => true; :::

  1. class _HomePageState extends State<HomePage>
  2. with AutomaticKeepAliveClientMixin {
  3. @override
  4. bool get wantKeepAlive => true;
  5. }

:::warning 可能有些小伙伴在搜索后会开始直接使用官方推荐的AutomaticKeepAliveClientMixin,通过在子页面的State类重写wantKeepAlivetrue 。 然而,如果你的代码和我上面的类似,body中并没有使用PageViewTabBarView,很不幸的告诉你,踩到坑了,这样是无效的 :::

:::info TabBarView+AutomaticKeepAliveClientMixin,3 个页面(A,B,C),从 C 页面直接切换到 A 页面时,B 页面会重新initState,而且已加载的数据(如数组),会丢失。 :::

  1. 在所有使用了AutomaticKeepAliveClientMixin父页面的build方法最上边调用 super.build(context);就可以了.
  2. @override
  3. Widget build(BuildContext context) {
  4. super.build(context);
  5. }

4.禁止左右滑动切换

  1. PageView( physics: NeverScrollableScrollPhysics(), // 禁用左右滑动 )

5.ListView, GridView中, 是否根据子组件的总长度来设置ListView的长度,默认值为false 。默认情况下,ListView的会在滚动方向尽可能多的占用空间。当ListView在一个无边界(滚动方向上)的容器中时,shrinkWrap必须为true

  1. shrinkWrap: true

图片.png