You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Flutter中堆叠BottomNavigationBar高度计算及显示异常求助

Flutter 底部导航栏堆叠组件问题解决

问题情况

  • 最初在bottomNavigationBar中使用Column堆叠组件,出现Column内容覆盖整个body的问题。
  • 用Container包裹Column并设置高度后,实现了底部堆叠,但存在底部溢出问题。
  • 给Column内组件添加GlobalKey,通过自定义函数获取高度,将函数调用放在initState后,堆叠导航栏不再显示。
  • 添加WidgetsBinding的PostFrameCallback也未解决,推测是组件未渲染导致高度为null。

原代码

import 'package:flutter/material.dart';

void main() {
  runApp(const MyApp());
}

class MyApp extends StatefulWidget {
  const MyApp({super.key});

  @override
  State<MyApp> createState() => _MyAppState();
}

class _MyAppState extends State<MyApp> {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(home: const MyHomePage());
  }
}

class MyHomePage extends StatefulWidget {
  const MyHomePage({super.key});

  @override
  State<MyHomePage> createState() => _MyHomePageState();
}

class _MyHomePageState extends State<MyHomePage> {
  List<BottomNavigationBarItem>? _items = [];
  String _value = "";
  int _index = 0;
  bool _showStackedBottomNavBar = false;

  final GlobalKey keyStackedBNBContainer = GlobalKey();
  final GlobalKey keyStackedBNB_BNB = GlobalKey();

  List<int> _listHeightOfStackedBNB = [];
  double _varForHeightOfStackedBNB = 0.0;

  @override
  void initState() {
    super.initState();

    if (_items != null) {
      _items?.add(
        BottomNavigationBarItem(icon: Icon(Icons.people), label: "People"),
      );
      _items?.add(
        BottomNavigationBarItem(icon: Icon(Icons.weekend), label: "Weekend"),
      );
      _items?.add(
        BottomNavigationBarItem(icon: Icon(Icons.message), label: "Message"),
      );
    }

    _varForHeightOfStackedBNB = _heightOfStackedBNB(
      keyStackedBNBContainer,
      keyStackedBNB_BNB,
    );
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        backgroundColor: Theme.of(context).primaryColor,
        title: const Text("Bottom sheet and navigation bar"),
      ),
      body: Column(
        children: [
          Text("########## $_value"),
          ElevatedButton(
            onPressed: () {
              setState(() {
                _showStackedBottomNavBar = !_showStackedBottomNavBar;
              });
            },
            child: Text("Click Me!"),
          ),
        ],
      ),

      bottomNavigationBar:
          (_showStackedBottomNavBar && _varForHeightOfStackedBNB > -1.0)
              ? Container(
                height: _varForHeightOfStackedBNB,
                child: Column(
                  mainAxisAlignment: MainAxisAlignment.end,
                  children: [
                    Container(
                      key: keyStackedBNBContainer,
                      padding: EdgeInsets.all(15.0),
                      height: 60.0,
                      width: double.infinity,
                      decoration: BoxDecoration(color: Colors.amberAccent),
                      child: const Text("Bottom Navigation Bar"),
                    ),
                    BottomNavigationBar(
                      key: keyStackedBNB_BNB,
                      items: _items!,
                      currentIndex: _index,
                      onTap: (int newIndex) {
                        setState(() {
                          _index = newIndex;
                          _value = "Current value is: ${_index.toString()}";
                        });
                      },
                    ),
                  ],
                ),
              )
              : Container(height: 60.0, color: Colors.red),
    );
  }

  double _heightOfStackedBNB(GlobalKey gk01, GlobalKey gk02) {
    double totalHeight = 0.0;
    bool isAnyHeightNull = false;

    double height01 = 0.0;
    if (gk01.currentContext?.size?.height == null) {
      isAnyHeightNull = true;
      height01 = gk01.currentContext?.size?.height ?? 0.0;
    }
    double height02 = 0.0;
    if (gk02.currentContext?.size?.height == null) {
      isAnyHeightNull = true;
      height02 = gk02.currentContext?.size?.height ?? 0.0;
    }

    totalHeight = height01 + height02;

    return isAnyHeightNull ? -1.0 : totalHeight;
  }
}

更新尝试(无效)

WidgetsBinding.instance.addPostFrameCallback((timestamp) {
  setState(() {
    _varForHeightOfStackedBNB = _heightOfStackedBNB(
      keyStackedBNBContainer,
      keyStackedBNB_BNB,
    );
  });
});

问题根源

  • 当_showStackedBottomNavBar为false时,带GlobalKey的子组件并未被渲染,currentContext为null,导致_heightOfStackedBNB返回-1。即使后续切换为true,_varForHeightOfStackedBNB的值仍为-1,堆叠导航栏无法显示。
  • 手动计算高度的思路冗余,bottomNavigationBar本身可以自动适配子组件的高度,无需硬设height。

修复方案

  1. 移除所有GlobalKey、高度计算相关的变量和函数。
  2. 给堆叠的Column设置mainAxisSize: MainAxisSize.min,让Column仅占用子组件的总高度,避免无限扩展。
  3. 去掉包裹Column的Container的height属性,让bottomNavigationBar自动适配高度。

修复后代码

import 'package:flutter/material.dart';

void main() {
  runApp(const MyApp());
}

class MyApp extends StatefulWidget {
  const MyApp({super.key});

  @override
  State<MyApp> createState() => _MyAppState();
}

class _MyAppState extends State<MyApp> {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(home: const MyHomePage());
  }
}

class MyHomePage extends StatefulWidget {
  const MyHomePage({super.key});

  @override
  State<MyHomePage> createState() => _MyHomePageState();
}

class _MyHomePageState extends State<MyHomePage> {
  List<BottomNavigationBarItem> _items = [];
  String _value = "";
  int _index = 0;
  bool _showStackedBottomNavBar = false;

  @override
  void initState() {
    super.initState();
    _items.addAll([
      const BottomNavigationBarItem(icon: Icon(Icons.people), label: "People"),
      const BottomNavigationBarItem(icon: Icon(Icons.weekend), label: "Weekend"),
      const BottomNavigationBarItem(icon: Icon(Icons.message), label: "Message"),
    ]);
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        backgroundColor: Theme.of(context).primaryColor,
        title: const Text("Bottom sheet and navigation bar"),
      ),
      body: Column(
        children: [
          Text("########## $_value"),
          ElevatedButton(
            onPressed: () {
              setState(() {
                _showStackedBottomNavBar = !_showStackedBottomNavBar;
              });
            },
            child: const Text("Click Me!"),
          ),
        ],
      ),
      bottomNavigationBar: _showStackedBottomNavBar
          ? Column(
              mainAxisSize: MainAxisSize.min,
              children: [
                Container(
                  padding: const EdgeInsets.all(15.0),
                  height: 60.0,
                  width: double.infinity,
                  decoration: const BoxDecoration(color: Colors.amberAccent),
                  child: const Text("Bottom Navigation Bar"),
                ),
                BottomNavigationBar(
                  items: _items,
                  currentIndex: _index,
                  onTap: (int newIndex) {
                    setState(() {
                      _index = newIndex;
                      _value = "Current value is: ${_index.toString()}";
                    });
                  },
                ),
              ],
            )
          : const SizedBox(height: 60, child: ColoredBox(color: Colors.red)),
    );
  }
}

说明

  • mainAxisSize: MainAxisSize.min让Column仅包裹子组件,不会占用额外空间。
  • 移除手动高度计算后,bottomNavigationBar会自动识别子组件的总高度,既不会覆盖body,也不会出现溢出问题。
  • 简化了_items的初始化逻辑,避免不必要的可空判断。

内容的提问来源于stack exchange,提问作者rusty

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.14 09:58:10