В следующем фрагменте кода я намерен установить высоту DropdownMenu
в зависимости от наличия/отсутствия экранной клавиатуры. Я также учел высоту других элементов, таких как AppBar
и TextField
, при расчете соответствующей высоты выпадающего меню (подробнее см. В коде). Мне не удалось должным образом обновить высоту переменной клавиатуры heightKeyboard
в моем коде, чтобы ее можно было использовать при вычислении heightDropdownMenu
. Высота клавиатуры остается необновленной, и, следовательно, высота раскрывающегося меню не адаптируется к наличию экранной клавиатуры, а некоторая его часть скрывается под клавиатурой, так что пользователь не может получить к ней доступ.
Что я пробовал: пытаясь это исправить, я попытался реализовать 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
и прослушать, когда изменится фокус, затем подождать несколько миллисекунд, чтобы дождаться появления клавиатуры и пересчитать размер.
Результат:
Код:
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"),
],
),
),
),
);
}
}
В моем основном приложении все шло нормально, я продолжал добавлять новые коды, но однажды, когда я нажал стрелку назад, произошло исключение приложения. Полезных сообщений тоже нет. Я перекодировал и обнаружил, что ошибка возникла после того, как я реализовал FocusNode. Ошибка возникает при переходе назад со страницы, содержащей focusNode. Подробности в новом вопросе. Надеюсь, вы снова сможете помочь.