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

Flutter:键盘弹出时如何上移Overlay Widget?

解决键盘遮挡custom_pointed_popup弹窗的问题

问题原因

键盘遮挡弹窗的核心原因有两点:

  • 创建弹窗时使用的MediaQuery.viewInsetsOf(context)是静态值,键盘弹出后不会自动更新,无法动态适配键盘高度。
  • Scaffold设置了resizeToAvoidBottomInset: false,页面整体不会为键盘留出空间,弹窗位置也无法自动调整。

解决方案

以下是修改后的完整代码,可解决键盘遮挡问题:

import 'package:custom_pointed_popup/custom_pointed_popup.dart';
import 'package:custom_pointed_popup/utils/triangle_painter.dart';
import 'package:flutter/material.dart';

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

  @override
  State<HomeScreen> createState() => _HomeScreenState();
}

class _HomeScreenState extends State<HomeScreen> {
  List<GlobalKey> keys = List.generate(25, (index) => GlobalKey());

  void show(GlobalKey key) {
    CustomPointedPopup popup = CustomPointedPopup(
      backgroundColor: Colors.grey.withOpacity(0.1),
      context: context,
      widthFractionWithRespectToDeviceWidth: 5,
      displayBelowWidget: true,
      triangleDirection: TriangleDirection.Straight,
      popupElevation: 10,
      item: CustomPointedPopupItem(
        // 使用Builder获取弹窗上下文,确保拿到实时的键盘偏移数据
        itemWidget: Builder(
          builder: (popupContext) {
            return SingleChildScrollView(
              child: Padding(
                // 用弹窗上下文获取键盘弹出后的实时viewInsets
                padding: MediaQuery.of(popupContext).viewInsets,
                child: Column(
                  mainAxisSize: MainAxisSize.min,
                  children: [
                    for (int i = 0; i < 5; i++) const Text('hello'),
                    TextField(
                      scrollPadding: EdgeInsets.zero,
                    )
                  ],
                ),
              ),
            );
          },
        ),
      ),
      onClickWidget: (onClickMenu) {
        print('popup item clicked');
        print(onClickMenu);
      },
      onDismiss: () {
        print('on dismissed called');
      },
    );
    popup.show(widgetKey: key);
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: GridView.builder(
        gridDelegate: const SliverGridDelegateWithFixedCrossAxisCount(
          crossAxisCount: 4,
          mainAxisSpacing: 32,
          crossAxisSpacing: 32,
          mainAxisExtent: 120,
        ),
        itemBuilder: (_, int pos) {
          return InkWell(
            onTap: () {
              show(keys[pos]);
            },
            child: Container(
              key: keys[pos],
              color: pos % 2 == 0 ? Colors.black : Colors.grey,
            ),
          );
        },
        itemCount: keys.length,
      ),
      // 移除该属性,让Scaffold自动为键盘调整布局;若业务必须保留,需额外监听键盘事件手动调整弹窗位置
      // resizeToAvoidBottomInset: false,
    );
  }
}

关键修改说明

  1. 移除resizeToAvoidBottomInset: false:让Scaffold自动响应键盘弹出事件,页面整体布局会向上偏移,带动弹窗位置适配。若业务必须保留该属性,可通过WidgetsBinding.instance.addObserver监听键盘高度变化,手动调整弹窗位置。
  2. 使用Builder获取弹窗上下文:确保能获取到键盘弹出后的实时MediaQuery.viewInsets,替代创建弹窗时的静态值。
  3. 添加SingleChildScrollView包裹弹窗内容:当键盘弹出后,弹窗内容可滚动,避免TextField被遮挡。
  4. 调整TextField的scrollPadding:设置为EdgeInsets.zero,配合外部的Padding确保滚动位置准确。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.12 08:03:10