如何根据屏幕键盘高度调整Flutter DropdownMenu的高度?
问题根源
- InkWell的onTap不触发:TextField本身会处理点击事件,外层InkWell的点击事件被拦截,导致你的print语句无法执行,也无法更新键盘高度。
- 键盘高度获取时机错误:点击TextField时键盘还未弹出,此时
MediaQuery.of(context).viewInsets.bottom仍为0,无法拿到正确的键盘高度。 - 未实时监听键盘状态变化:键盘弹出/收起是异步过程,需要监听MediaQuery的变化来实时更新DropdownMenu高度。
解决方案
通过监听键盘状态变化,实时计算DropdownMenu高度,以下是修改后的完整代码:
import 'dart:ui'; import 'package:flutter/material.dart'; void main() { runApp(const MyApp()); } class MyApp extends StatelessWidget { const MyApp({super.key}); @override Widget build(BuildContext context) { return MaterialApp( title: 'Flutter Demo', theme: ThemeData( colorScheme: ColorScheme.fromSeed(seedColor: Colors.deepPurple), useMaterial3: true, ), home: const MyHomePage(title: 'Flutter Demo Home Page'), ); } } const List<String> list = <String>[ "A", "B", "C", "D", "E", "F", "G", "H", "I", "J", ]; class MyHomePage extends StatefulWidget { const MyHomePage({super.key, required this.title}); final String title; @override State<MyHomePage> createState() => _MyHomePageState(); } class _MyHomePageState extends State<MyHomePage> { final GlobalKey? _key01 = GlobalKey(); final GlobalKey? _key02 = GlobalKey(); late final TextEditingController firstController; late Size screenSize; double screenWidth = 0; double screenHeight = 0; double heightAppBar = 0; double heightTextField = 0; double heightOthersCummulative = 0; double heightAdjustment = 60; double heightDropdownMenu = 150; // 默认高度 late String dropdownValue = list.first; String result = ""; String effective_available_screen_height = ""; String dimensions = ""; FlutterView view = WidgetsBinding.instance.platformDispatcher.views.first; late Size size; double width = 0; double height = 0; double height01 = 0; @override void initState() { super.initState(); firstController = TextEditingController(); WidgetsBinding.instance.addPostFrameCallback((timeStamp) { setState(() { heightAppBar = _key01?.currentContext?.size?.height ?? 0; heightTextField = _key02?.currentContext?.size?.height ?? 0; updateDropdownHeight(); dimensions = "KeyboardHeight=${MediaQuery.of(context).viewInsets.bottom}\nDropdownMenuHeight=${heightDropdownMenu}\nAppBarHeight=${heightAppBar}\nTextFieldHeight=${heightTextField}"; }); }); // 监听每帧变化,实时更新键盘高度和下拉菜单高度 WidgetsBinding.instance.addPersistentFrameCallback((_) { if (mounted) { setState(() { updateDropdownHeight(); }); } }); } // 统一计算DropdownMenu高度 void updateDropdownHeight() { final currentKeyboardHeight = MediaQuery.of(context).viewInsets.bottom; if (heightAppBar > 0 && heightTextField > 0) { heightDropdownMenu = screenHeight - heightAppBar - heightTextField - currentKeyboardHeight - heightOthersCummulative - heightAdjustment; // 确保高度不会为负数 heightDropdownMenu = heightDropdownMenu.clamp(100, double.infinity); } else { heightDropdownMenu = 150; } } @override void dispose() { firstController.dispose(); super.dispose(); } @override Widget build(BuildContext context) { screenSize = MediaQuery.of(context).size; screenWidth = screenSize.width; screenHeight = screenSize.height; Size ph_size = view.physicalSize; double ph_height = ph_size.height; size = MediaQuery.of(context).size; width = size.width; height = size.height; final padding = MediaQuery.of(context).viewPadding; height01 = height - padding.top - padding.bottom; effective_available_screen_height = "$height01"; double keyboard_height = MediaQuery.of(context).viewInsets.bottom; return Scaffold( appBar: AppBar( key: _key01, backgroundColor: Theme.of(context).colorScheme.inversePrimary, title: Text(widget.title), ), body: Container( padding: const EdgeInsets.all(5.0), child: Column( children: [ Container( child: Row( children: [ Expanded( flex: 5, child: Container( padding: const EdgeInsets.all(5.0), // 移除无效的InkWell child: TextField( key: _key02, style: const TextStyle( fontSize: 16, ), controller: firstController, keyboardType: TextInputType.number, onChanged: (value) { setState(() { result = value; }); }, ), ), ), Expanded( flex: 5, child: Container( padding: const EdgeInsets.all(5.0), child: DropdownMenu<String>( menuHeight: heightDropdownMenu, textStyle: const TextStyle( fontSize: 16.0, ), initialSelection: dropdownValue, onSelected: (String? value) { if (value != null) { setState(() { dropdownValue = value; }); } }, dropdownMenuEntries: list.map<DropdownMenuEntry<String>>((String value) { return DropdownMenuEntry<String>( value: value, label: value); }).toList(), ), ), ), ], ), ), Text("Result = $result"), Text("Total physical height = $ph_height"), Text("Total logical height = $height"), Text("Onscreen Keyboard height = $keyboard_height"), Text( "Working Height Available (logical) = $effective_available_screen_height"), Text("Dimensions: $dimensions"), ], ), ), ); } }
关键修改说明
- 移除无用的InkWell:TextField的点击事件会优先响应,外层InkWell的onTap不会触发,直接删除即可。
- 添加键盘状态监听:通过
addPersistentFrameCallback监听每帧变化,实时获取当前键盘高度并更新DropdownMenu高度。 - 统一高度计算逻辑:新增
updateDropdownHeight方法集中处理高度计算,同时用clamp确保高度不会为负数。 - 初始化时获取控件真实高度:在
addPostFrameCallback中获取AppBar和TextField的实际高度,保证计算基础准确。
内容的提问来源于stack exchange,提问作者rusty
相关产品推荐
相关产品推荐

