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

Flutter组合BottomNavigationBar与页面时出现底部溢出4.7像素错误

Flutter嵌套页面底部溢出问题修复

问题描述

在Flutter项目中添加BottomNavigationBar并引入ReminderHomePage页面,点击「Home」标签时显示该页面。两者单独运行均正常,但组合后出现「BOTTOM OVERFLOWED BY 4.7 PIXEL」的底部溢出错误。

相关代码

导航栏代码(MainPage)

import 'package:flutter/material.dart';
import 'package:medreminder/NewsArticle/newsmain.dart';
import 'package:medreminder/Reminder/ui/home_reminder.dart';
import 'package:medreminder/Reminder/ui/widgets/add_remindbar.dart';
import 'package:medreminder/home_page.dart';
import 'package:medreminder/profile_page.dart';
import 'package:medreminder/settings_page.dart';
import 'package:get/get.dart';
import 'package:intl/intl.dart';
import 'package:medreminder/Reminder/ui/theme.dart';

void main() => runApp(MaterialApp(home: MainPage()));

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

  @override
  State<MainPage> createState() => _MainPageState();
}

class _MainPageState extends State<MainPage> {
  List <Widget> pages = [
    ReminderHomePage(),
    SettingPage(),
    ProfilePage()
  ];
  int currentIndex = 0;
  void onTap(int index){
    setState(() {
      currentIndex = index;
    });
  }
  @override
  Widget build(BuildContext context) {
    return Scaffold(

      body: Container(
        width: MediaQuery.of(context).size.width,
        height: MediaQuery.of(context).size.height * 0.4,
        child: pages[currentIndex]
      ),
      bottomNavigationBar: BottomNavigationBar(
        type: BottomNavigationBarType.shifting,
        onTap: onTap,
        currentIndex: currentIndex,
        selectedItemColor: bluishClr,
        unselectedItemColor: Colors.black,
        showUnselectedLabels: false,
        showSelectedLabels: false,
        items: [
          BottomNavigationBarItem(label: "Home", icon: Icon(Icons.home)),
          BottomNavigationBarItem(label: "Settings", icon: Icon(Icons.settings)),
          BottomNavigationBarItem(label: "Profile", icon: Icon(Icons.account_circle)),
          
        ],
      ),
    );
  }
}

ReminderHomePage页面代码

import 'package:date_picker_timeline/date_picker_timeline.dart';
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:get/get.dart';
import 'package:google_fonts/google_fonts.dart';
import 'package:medreminder/Reminder/services/notification_services.dart';
import 'package:medreminder/Reminder/services/theme_services.dart';
import 'package:intl/intl.dart';
import 'package:medreminder/Reminder/ui/theme.dart';
import 'package:medreminder/Reminder/ui/widgets/add_remindbar.dart';
import 'package:medreminder/Reminder/ui/widgets/button.dart';
import 'package:medreminder/Reminder/ui/widgets/add_remindbar.dart';

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

  @override
  State<ReminderHomePage> createState() => _ReminderHomePageState();
}

class _ReminderHomePageState extends State<ReminderHomePage> {
  DateTime _selectedDate = DateTime.now();
  var notifyHelper;
  @override
  void initState() {
    super.initState();
    notifyHelper=NotifyHelper();
    notifyHelper.initializeNotification();
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      resizeToAvoidBottomInset: false,
      appBar: _appBar(),
      backgroundColor: context.theme.backgroundColor,
      body: Column(
        children: [
          _addTaskBar(),
          _addDateBar(),
        ],
        ),
    );
  }
  _addDateBar(){
    return Container(
            margin: const EdgeInsets.only(top: 20, left: 20),
            child: DatePicker(
              DateTime.now(),
              height: 100,
              width: 80,
              initialSelectedDate: DateTime.now(),
              selectionColor: Color(0xFFAAB6FB),
              selectedTextColor: Colors.white,
              dateTextStyle: GoogleFonts.lato(
                textStyle: TextStyle(
                    fontSize: 20,
                    fontWeight: FontWeight.w600,
                    color:Colors.grey
                ),
              ),
              dayTextStyle: GoogleFonts.lato(
                textStyle: TextStyle(
                    fontSize: 16,
                    fontWeight: FontWeight.w600,
                    color:Colors.grey
                ),
              ),
              monthTextStyle: GoogleFonts.lato(
                textStyle: TextStyle(
                    fontSize: 14,
                    fontWeight: FontWeight.w600,
                    color:Colors.grey
                ),
              ),
              onDateChange: (date){
                    _selectedDate=date;
              },
            ),
          );
  }
  _addTaskBar(){
    return Container(
            margin: const EdgeInsets.only(left: 20, right: 20, top: 5),
            child: Row(
              mainAxisAlignment: MainAxisAlignment.spaceBetween,
              children: [
                Container(
                  margin: const EdgeInsets.symmetric(horizontal: 20),
                  child: Column(
                    crossAxisAlignment: CrossAxisAlignment.start,
                    children: [
                      Text(DateFormat.yMMMMd().format(DateTime.now()),
                      style: subHeadingStyle,
                      ),
                      Text("Today", 
                      style: headingStyle,
                      )
                    ],
                  ),
                ),
                MyButton(label: "Add Reminder", onTap: ()=>Get.to(AddReminderPage()))
              ],
            ),
          );
  }

  _appBar(){
    return AppBar(
      elevation: 0,
      backgroundColor: context.theme.backgroundColor,
      leading: GestureDetector(
        onTap: (){
            ThemeService().switchTheme();
            notifyHelper.displayNotification(
              title:"Theme Changed!",
              body: Get.isDarkMode?"Activated Light Theme!":"Activated Dark Theme!"
            );

            notifyHelper.scheduledNotification();
        },
        child: Icon(Get.isDarkMode ?Icons.wb_sunny_outlined:Icons.nightlight_round,
        size: 20,
          color:Get.isDarkMode ? Colors.white:Colors.black
        ),
      ),
      actions: [
        CircleAvatar(
          backgroundImage: AssetImage(
            "images/profile.png"
          ),
        ),
        SizedBox(width: 20,),
      ],
    );
  }
}

错误信息

══╡ EXCEPTION CAUGHT BY RENDERING LIBRARY ╞═════════════════════════════════════════════════════════
The following assertion was thrown during layout:
A RenderFlex overflowed by 2.7 pixels on the bottom.

The relevant error-causing widget was:
  Column
  Column:file:///D:/Kuliah/Mata%20Kuliah/Pemrograman%20Mobile/medicine_reminder/code/lib/Reminder/ui/home_reminder.dart:38:13

The overflowing RenderFlex has an orientation of Axis.vertical.
The edge of the RenderFlex that is overflowing has been marked in the rendering with a yellow and
black striped pattern. This is usually caused by the contents being too big for the RenderFlex.
Consider applying a flex factor (e.g. using an Expanded widget) to force the children of the
RenderFlex to fit within the available space instead of being sized to their natural size.
This is considered an error condition because it indicates that there is content that cannot be
seen. If the content is legitimately bigger than the available space, consider clipping it with a
ClipRect widget before putting it in the flex, or using a scrollable container rather than a Flex,
like a ListView.
The specific RenderFlex in question is: RenderFlex#7023a relayoutBoundary=up1 OVERFLOWING:
  needs compositing
  creator: Column ← KeyedSubtree-[GlobalKey#e59a5] ← _BodyBuilder ← MediaQuery ←
    LayoutId-[<_ScaffoldSlot.body>] ← CustomMultiChildLayout ← _ActionsMarker ← Actions ←
    AnimatedBuilder ← DefaultTextStyle ← AnimatedDefaultTextStyle ← _InkFeatures-[GlobalKey#01a94 ink
    renderer] ← ⋯
  parentData: offset=Offset(0.0, 56.0); id=_ScaffoldSlot.body (can use size)
  constraints: BoxConstraints(0.0<=w<=502.0, 0.0<=h<=173.3)
  size: Size(502.0, 173.3)
  direction: vertical
  mainAxisAlignment: start
  mainAxisSize: max
  crossAxisAlignment: center
  verticalDirection: down
◢◤◢◤◢◤◢◤◢◤◢◤◢◤◢◤◢◤◢◤◢◤◢◤◢◤◢◤◢◤◢◤◢◤◢◤◢◤◢◤◢◤◢◤◢◤◢◤◢◤◢◤◢◤◢◤◢◤◢◤◢◤◢◤◢◤◢◤◢◤◢◤◢◤◢◤◢◤◢◤◢◤◢◤◢◤◢◤◢◤◢◤◢◤◢◤◢◤◢◤
═══════════════════════════════════════════════════════════════════════════════════════════════════

错误截图

底部溢出错误截图

解决方案

问题根源

MainPage中给body的Container设置了固定高度MediaQuery.of(context).size.height * 0.4,而ReminderHomePage本身是包含AppBar和Column内容的完整Scaffold,嵌套后可用高度不足以容纳内部所有元素,导致Column溢出。

修复步骤

  1. 移除MainPage中body的固定高度限制
    修改MainPage的body部分,直接将页面作为Scaffold的body,让其自适应剩余空间:

    body: pages[currentIndex],
    

    或者保留Container但去掉固定高度:

    body: Container(
      width: MediaQuery.of(context).size.width,
      child: pages[currentIndex],
    ),
    
  2. 可选:避免嵌套Scaffold(优化建议)
    如果不需要多个AppBar,可以将ReminderHomePage的内容改为不带Scaffold的Widget,只保留AppBar和body内容,然后在MainPage的Scaffold中统一管理AppBar。修改后的ReminderHomePage示例:

    @override
    Widget build(BuildContext context) {
      return Column(
        children: [
          _appBar(), // 这里的_appBar改为返回PreferredSizeWidget
          _addTaskBar(),
          _addDateBar(),
        ],
      );
    }
    
    PreferredSizeWidget _appBar(){
      return AppBar(
        // 原AppBar代码保持不变
      );
    }
    

    同时在MainPage中设置AppBar:

    return Scaffold(
      appBar: (pages[currentIndex] is ReminderHomePage) ? (pages[currentIndex] as ReminderHomePage)._appBar() : null,
      body: pages[currentIndex],
      // 底部导航栏代码不变
    );
    

额外优化

如果ReminderHomePage的内容后续可能更多,可以将其内部的Column改为ListView,避免未来再次出现溢出:

body: ListView(
  children: [
    _addTaskBar(),
    _addDateBar(),
  ],
),

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.12 01:50:33