首先,我的下拉菜单高度没有调整为屏幕弹出键盘占用所留下的空间,这现在在我的旧问题中得到了解决。该解决方案利用
FocusNode
和其他辅助代码来解决我的问题。但由于新代码的实施,可能出现了一个新问题。当用户单击 TextButton
时,我的应用程序允许导航到不同的页面,并且通过单击后退箭头按钮,用户可以返回到上一个主菜单页面。
问题:当用户点击TextButton进入其他页面时,如果不点击
TextField
而是点击后退箭头,不会出现异常,用户可以轻松地前后移动这样。但是当用户点击TextButton,进入下一页,然后点击TextField
然后按后退箭头时,用户返回到主菜单页面,但同时也会发生异常。发生此异常后,用户无法再选择 TextButton 选项来导航到使用多个 TextButton 实现的任何页面。用户界面冻结。这就是我们如何复制下面所示代码的异常:
以下是我的
main.dart
页面内容:
import 'package:ask__widget_and_app_effective_height/my_home_page.dart';
import 'package:flutter/material.dart';
void main() {
runApp(const MyApp());
}
class MyApp extends StatelessWidget {
const MyApp({super.key});
@override
Widget build(BuildContext context) {
return const MaterialApp(
debugShowCheckedModeBanner: false,
home: Screen__Menu(),
);
}
}
class Screen__Menu extends StatelessWidget {
const Screen__Menu({super.key});
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
backgroundColor: Colors.blue,
title: Text("Demo App"),
),
body: ListView(
children: [
TextButton(
child: const Text("MyHomePage"),
onPressed: () {
Navigator.push(context,
MaterialPageRoute(builder: (context) => MyHomePage()));
},
),
],
),
);
}
}
以下是我的
my_home_page.dart
页面内容:
import 'dart:ui';
import 'package:flutter/material.dart';
const List<String> list = <String>[
"A",
"B",
"C",
"D",
"E",
"F",
"G",
"H",
"I",
"J",
];
class MyHomePage extends StatefulWidget {
const MyHomePage({super.key});
@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 = 48;
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: const Text("Demo App"),
),
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"),
],
),
),
),
);
}
}
更新:
我还尝试将 Navigator.push 包装在 try-catch 块中,并使用 FloatingActionButton 实现 Navigator.pop。 Navigator.pop 也包含在 try-catch 块中。
Navigator.push:(现在)(遗憾的是,这没有捕获任何异常。)
try {
Navigator.push(context,
MaterialPageRoute(builder: (context) => MyHomePage()));
} catch (e) {
print("########## Caught exception: $e");
} finally {
print("########## Navigator.push completed!");
}
Navigator.pop:(现在)(这也没有捕获任何异常。但是当尝试前面所说的异常重现方法两次时,似乎会发生异常。)
FloatingActionButton(
child: Icon(Icons.arrow_back),
onPressed: () {
try {
Navigator.pop(context);
} catch (e) {
print("########## Caught exception: $e");
} finally {
print("########## Finished Navigator.pop!");
}
},
),
我不知道还能尝试什么,代码哪里出了问题?
调试控制台中描述的错误与在不再存在的小部件中设置状态有关。你需要做的就是改变
void _onFocusChange() {
Future.delayed(const Duration(milliseconds: 500), () {
setState(() {
heightKeyboard = MediaQuery.of(context).viewInsets.bottom;
setDropdownMenuHeight(heightAppBar, heightTextField, heightKeyboard);
});
});
}
到
void _onFocusChange() {
Future.delayed(const Duration(milliseconds: 500), () {
if(mounted) {
setState(() {
heightKeyboard = MediaQuery.of(context).viewInsets.bottom;
setDropdownMenuHeight(heightAppBar, heightTextField, heightKeyboard);
});
}
});
}
每次设置状态时最好始终检查小部件是否已安装。