在下面的代码中,我打算根据屏幕键盘的存在/不存在来设置
DropdownMenu
的高度。在计算下拉菜单的适当高度时,我还考虑了AppBar
和TextField
等其他元素的高度(具体请参阅代码)。我无法在代码中正确更新键盘 heightKeyboard
变量的高度,以便 heightDropdownMenu
的计算可以使用它。 heightKeyboard 保持未更新,因此下拉菜单的高度不适应屏幕键盘的存在,并且它的某些部分隐藏在键盘下方,使得用户无法访问它们。
我尝试过的:为了修复它,我尝试在
InkWell
周围实现 TextField
并在其 onTap
属性中尝试更新键盘高度,然后更新下拉高度,但这并没有'似乎工作正常,而且我也没有看到其中的 print() 函数也工作,因此无法判断值是否正在更新。
希望有人能帮助我。谢谢你。
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 heightKeyboard = 0;
double heightOthersCummulative = 0;
double heightAdjustment = 60;
double heightDropdownMenu = 0;
void setDropdownMenuHeight(
double heightAppBar, double heightTextField, double heightKeyboard) {
if (heightAppBar > 0 && heightTextField > 0) {
heightDropdownMenu = screenHeight -
heightAppBar -
heightTextField -
heightKeyboard -
heightOthersCummulative -
heightAdjustment;
// return heightDropdownMenu;
} else {
heightDropdownMenu = 150;
// return heightDropdownMenu;
}
}
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 ?? -1;
heightTextField = _key02?.currentContext?.size?.height ?? -1;
heightKeyboard = MediaQuery.of(context).viewInsets.bottom;
setDropdownMenuHeight(heightAppBar, heightTextField, heightKeyboard);
dimensions =
"KeyboardHeight=${heightKeyboard}\nDropdownMenuHeight=${heightDropdownMenu}\nAppBarHeight=${_key01?.currentContext?.size?.height}\nTextFieldHeight=${_key02?.currentContext?.size?.height}";
});
});
}
@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";
// Height of Keyboard when onscreen (ohterwise zero):
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),
child: InkWell(
onTap: () {
setState(() {
heightKeyboard =
MediaQuery.of(context).viewInsets.bottom;
setDropdownMenuHeight(
heightAppBar, heightTextField, heightKeyboard);
// THESE PRINT DOES NOT SEEM TO PRINT ONTAP:
print("==========[InkWell]$heightDropdownMenu");
print("========[InkWell](kbdHt=)$heightKeyboard");
});
},
child: TextField(
key: _key02,
style: const TextStyle(
fontSize: 16,
),
controller: firstController,
keyboardType: TextInputType.number,
onChanged: (value) {
setState(() {
result = value;
/*
// The following gave error:
dimensions =
"${_key01?.currentContext.size.height}";
*/
dimensions =
"${_key01?.currentContext?.size?.height}";
});
},
),
),
),
),
Expanded(
flex: 5,
child: Container(
padding: const EdgeInsets.all(5.0),
child: DropdownMenu<String>(
menuHeight: heightDropdownMenu,
// menuHeight: 300,
textStyle: const TextStyle(
fontSize: 16.0,
),
initialSelection: dropdownValue,
onSelected: (String? value) {
print("==========[DropdownMenu]$heightDropdownMenu");
print(
"========[DropdownMenu](kbdHt=)$heightKeyboard");
setState(() {
// codes here
});
},
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
会拦截手势,你可以做的是使用FocusNode
,将其设置为TextField
en 监听焦点变化,然后等待几毫秒键盘出现并重新计算尺寸。
结果:
代码:
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 heightKeyboard = 0;
double heightOthersCummulative = 0;
double heightAdjustment = 60;
double heightDropdownMenu = 0;
void setDropdownMenuHeight(
double heightAppBar, double heightTextField, double heightKeyboard) {
if (heightAppBar > 0 && heightTextField > 0) {
heightDropdownMenu = screenHeight -
heightAppBar -
heightTextField -
heightKeyboard -
heightOthersCummulative -
heightAdjustment;
// return heightDropdownMenu;
} else {
heightDropdownMenu = 150;
// return heightDropdownMenu;
}
}
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;
final FocusNode _focusNode = FocusNode();
@override
void initState() {
super.initState();
firstController = TextEditingController();
_focusNode.addListener(_onFocusChange);
WidgetsBinding.instance.addPostFrameCallback((timeStamp) {
setState(() {
heightAppBar = _key01.currentContext?.size?.height ?? -1;
heightTextField = _key02.currentContext?.size?.height ?? -1;
heightKeyboard = MediaQuery.of(context).viewInsets.bottom;
setDropdownMenuHeight(heightAppBar, heightTextField, heightKeyboard);
dimensions =
"KeyboardHeight=$heightKeyboard\nDropdownMenuHeight=$heightDropdownMenu\nAppBarHeight=${_key01.currentContext?.size?.height}\nTextFieldHeight=${_key02.currentContext?.size?.height}";
});
});
}
void _onFocusChange() {
Future.delayed(const Duration(milliseconds: 500), () {
setState(() {
heightKeyboard = MediaQuery.of(context).viewInsets.bottom;
setDropdownMenuHeight(heightAppBar, heightTextField, heightKeyboard);
});
});
}
@override
void dispose() {
_focusNode.removeListener(_onFocusChange);
_focusNode.dispose();
firstController.dispose();
super.dispose();
}
@override
Widget build(BuildContext context) {
screenSize = MediaQuery.of(context).size;
screenWidth = screenSize.width;
screenHeight = screenSize.height;
Size phSize = view.physicalSize;
double phHeight = phSize.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";
// Height of Keyboard when onscreen (ohterwise zero):
double keyboardHeight = MediaQuery.of(context).viewInsets.bottom;
return Scaffold(
appBar: AppBar(
key: _key01,
backgroundColor: Theme.of(context).colorScheme.inversePrimary,
title: Text(widget.title),
),
body: GestureDetector(
onTap: () {
FocusScope.of(context).requestFocus(FocusNode());
},
child: 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),
child: TextField(
key: _key02,
style: const TextStyle(
fontSize: 16,
),
controller: firstController,
keyboardType: TextInputType.number,
focusNode: _focusNode,
onChanged: (value) {
setState(() {
result = value;
/*
// The following gave error:
dimensions =
"${_key01?.currentContext.size.height}";
*/
dimensions =
"${_key01.currentContext?.size?.height}";
});
},
),
),
),
Expanded(
flex: 5,
child: Container(
padding: const EdgeInsets.all(5.0),
child: DropdownMenu<String>(
menuHeight: heightDropdownMenu,
// menuHeight: 300,
textStyle: const TextStyle(
fontSize: 16.0,
),
initialSelection: dropdownValue,
onSelected: (String? value) {
print(
"==========[DropdownMenu]$heightDropdownMenu");
print(
"========[DropdownMenu](kbdHt=)$heightKeyboard");
setState(() {
// codes here
});
},
dropdownMenuEntries: list
.map<DropdownMenuEntry<String>>((String value) {
return DropdownMenuEntry<String>(
value: value, label: value);
}).toList(),
),
),
),
],
),
),
Text("Result = $result"),
Text("Total physical height = $phHeight"),
Text("Total logical height = $height"),
Text("Onscreen Keyboard height = $keyboardHeight"),
Text(
"Working Height Available (logical) = $effective_available_screen_height"),
Text("Dimensions: $dimensions"),
],
),
),
),
);
}
}