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

Flutter中BottomNavigationBar收起键盘时白块闪烁问题排查

Flutter底部自定义导航栏键盘收起时白块闪烁问题

问题描述

自定义底部导航栏(通过Container实现),点击TextField弹出键盘后收起,底部组件区域会出现白块闪烁现象。

复现代码

import 'package:flutter/material.dart';
import 'package:flutter/services.dart';

void main() {
  runApp(const MyApp());
  SystemChrome.setSystemUIOverlayStyle(const SystemUiOverlayStyle(
    statusBarColor: Colors.transparent,
    systemNavigationBarColor: Colors.transparent,
  ));
}

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

  @override
  Widget build(BuildContext context) {
    return const MaterialApp(
      title: 'Flutter Demo',
      home: MyHomePage(title: 'Flutter Demo Home Page'),
    );
  }
}

class MyHomePage extends StatefulWidget {
  const MyHomePage({super.key, required this.title});

  final String title;

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

class _MyHomePageState extends State<MyHomePage> {
  int _counter = 0;

  void _incrementCounter() {
    setState(() {
      _counter++;
    });
  }

  @override
  Widget build(BuildContext context) {
    return AnnotatedRegion<SystemUiOverlayStyle>(
      value: SystemUiOverlayStyle(
        systemNavigationBarColor: Colors.black.withOpacity(0),
      ),
      child: Scaffold(
        extendBody: true,
        appBar: AppBar(
          backgroundColor: Theme.of(context).colorScheme.inversePrimary,
          title: Text(widget.title),
        ),
        bottomNavigationBar: SafeArea(
          child: Container(
            decoration: BoxDecoration(
              color: Theme.of(context).colorScheme.surface,
              borderRadius: BorderRadius.circular(12),
              boxShadow: [
                BoxShadow(color: Theme.of(context).colorScheme.outlineVariant.withOpacity(0.5), blurRadius: 12),
              ],
            ),
            margin: const EdgeInsets.only(left: 38, right: 38, bottom: 7),
            padding: const EdgeInsets.symmetric(horizontal: 14, vertical: 4),
            child: Row(
              children: [
                FilledButton(onPressed: () {}, child: const Text('add')),
                FilledButton(onPressed: () {}, child: const Text('add')),
              ],
            ),
          ),
        ),
        body: CustomScrollView(
          slivers: [
            const SliverToBoxAdapter(
              child: Column(
                children: [
                  ListTile(title: Text('Item 1')),
                  ListTile(title: Text('Item 2')),
                  ListTile(title: Text('Item 3')),
                  ListTile(title: Text('Item 4')),
                  ListTile(title: Text('Item 5')),
                  ListTile(title: Text('Item 6')),
                  ListTile(title: Text('Item 6')),
                  ListTile(title: Text('Item 6')),
                  ListTile(title: Text('Item 7')),
                  ListTile(title: Text('Item 8')),
                  ListTile(title: Text('Item 8')),
                ],
              ),
            ),
            const SliverToBoxAdapter(
              child: TextField(),
            ),
            SliverList.builder(
                itemBuilder: (v, a) {
                  return Card(
                    child: ListTile(title: Text('Item $a')),
                  );
                },
                itemCount: 10),
          ],
        ),
      ),
    );
  }
}

问题原因

  1. Scaffold设置了extendBody: true,允许body内容延伸至底部导航栏下方,但键盘收起的布局重绘过程中,底部导航栏区域的背景未被及时填充,露出了默认白色背景。
  2. 全局和AnnotatedRegion设置了透明系统导航栏,搭配SafeArea使用时,键盘收起的动画过渡阶段会出现短暂布局空白。

解决方案

方案1:给Scaffold设置统一背景色

给Scaffold添加与底部导航栏一致的背景色,确保重绘时底部区域不会露出白色:

Scaffold(
  extendBody: true,
  backgroundColor: Theme.of(context).colorScheme.surface, // 添加该行
  // 其余代码不变
)

方案2:给底部导航栏外层添加背景容器

若不想修改整个页面背景色,可给bottomNavigationBar的SafeArea外层包裹同色容器填充底部区域:

bottomNavigationBar: Container(
  color: Theme.of(context).colorScheme.surface, // 填充背景色
  child: SafeArea(
    child: Container(
      // 原有底部导航栏代码
    ),
  ),
)

方案3:调整系统导航栏设置(可选)

若无需透明导航栏,可修改SystemChrome和AnnotatedRegion中的systemNavigationBarColor为非透明色,避免过渡阶段空白:

SystemChrome.setSystemUIOverlayStyle(const SystemUiOverlayStyle(
  statusBarColor: Colors.transparent,
  systemNavigationBarColor: Colors.white, // 设置为非透明色
));

// 同步修改AnnotatedRegion中的值
AnnotatedRegion<SystemUiOverlayStyle>(
  value: SystemUiOverlayStyle(
    systemNavigationBarColor: Colors.white,
  ),
  // 其余代码不变
)

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.17 00:59:59