如何在 flutter 中的两个屏幕之间导航并显示键盘?
How to navigate between two screens in flutter and show keyboard?
我有一些下一个(简化的)小部件树结构:
- home (stack of widgets)
- page container
- editText field
如您所见,编辑文本将始终位于页面顶部,我将与 Navigator.of(context)
事务交换。
问题:当我聚焦editText
时键盘出现。当用户开始输入时,有时我需要在 page container
内推送另一个屏幕。当我使用 Navigator.of()
时 - editText
没有焦点并且键盘按下。
需要什么: 我需要以某种方式在 page container
中使用 Navigator
进行转换 (push/pop/replace) 并保持键盘仍然向上 (保持 editText 的焦点)。
你知道怎么做吗?
您的用例看起来很奇怪,但我想您有充分的理由遵循此设置。
无论如何,问题是当调用 Navigator.push
时,TextField
没有聚焦。这不是一个错误,而是一个预期的功能(我认为)是为了防止键盘跟随您进入下一个没有 TextField
的屏幕。但是我知道这对您的用例来说是个问题。
我的解决方案(不是我承认的最漂亮的,但我唯一能做的)是手动强制焦点回到 TextField
。您需要两个组件:
- 一个
FocusNode
关联到您的 TextField
以收听检查您的 TextField
是否从专注变为不专注。如果设置了focusOnNextUnfocus
,在unfocus 后应该重新请求focus
focusOnNextUnfocus
在推送之前设置为 true
的布尔值,一旦再次请求焦点,它将设置为 false。
这是对您提供的代码的改编:
import 'package:flutter/material.dart';
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: MyHomePage(title: 'Flutter Demo Home Page'),
);
}
}
class MyHomePage extends StatefulWidget {
MyHomePage({Key? key, required this.title}) : super(key: key);
final String title;
@override
_MyHomePageState createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
/// Handles the focus state of our text field
final focusNode = FocusNode();
/// A bool to keep track on whether we should refocus after
/// unfocus. This will be set to `true` before pushing
var focusOnNextUnfocus = false;
int _counter = 0;
void _incrementCounter() {
setState(() {
_counter++;
});
}
@override
void initState() {
focusNode.addListener(() {
// If we no longer have the focus and should refocus, we refocus
if (!focusNode.hasFocus && focusOnNextUnfocus) {
focusNode.requestFocus();
focusOnNextUnfocus = false; // Reset to false once it has been processed
}
});
super.initState();
}
@override
void dispose() {
focusNode.dispose();
super.dispose();
}
@override
Widget build(BuildContext context) {
late BuildContext anotherContext;
final edit = TextField(
focusNode: focusNode,
onChanged: (String value) async {
if (value.length > 4) {
// Pop does not unfocus so no worries here
Navigator.pop(anotherContext);
} else if (value.length > 3) {
// Push DOES unfocus, so we need to set focusOnNextUnfocus to true
focusOnNextUnfocus = true;
Navigator.of(anotherContext).push(
MaterialPageRoute(builder: (_) {
return Builder(builder: (context) {
return Another();
});
}),
);
}
},
);
final scaffold = MaterialApp(
home: Scaffold(
appBar: AppBar(
title: Text(widget.title),
),
body: Builder(
builder: (context) {
anotherContext = context;
return Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Text(
'You have pushed the button this many times:',
),
Text(
'$_counter',
style: Theme.of(context).textTheme.headline4,
),
],
),
);
},
),
floatingActionButton: FloatingActionButton(
onPressed: _incrementCounter,
tooltip: 'Increment',
child: Icon(Icons.add),
),
),
);
return Scaffold(
body: Stack(
children: [
Positioned(child: scaffold),
Align(
alignment: Alignment.center,
child: Padding(
padding: EdgeInsets.symmetric(horizontal: 16),
child: edit,
),
),
],
),
);
}
}
class Another extends StatelessWidget {
const Another({Key? key}) : super(key: key);
@override
Widget build(BuildContext context) {
return Container(
color: Colors.red,
);
}
}
我有一些下一个(简化的)小部件树结构:
- home (stack of widgets)
- page container
- editText field
如您所见,编辑文本将始终位于页面顶部,我将与 Navigator.of(context)
事务交换。
问题:当我聚焦editText
时键盘出现。当用户开始输入时,有时我需要在 page container
内推送另一个屏幕。当我使用 Navigator.of()
时 - editText
没有焦点并且键盘按下。
需要什么: 我需要以某种方式在 page container
中使用 Navigator
进行转换 (push/pop/replace) 并保持键盘仍然向上 (保持 editText 的焦点)。
你知道怎么做吗?
您的用例看起来很奇怪,但我想您有充分的理由遵循此设置。
无论如何,问题是当调用 Navigator.push
时,TextField
没有聚焦。这不是一个错误,而是一个预期的功能(我认为)是为了防止键盘跟随您进入下一个没有 TextField
的屏幕。但是我知道这对您的用例来说是个问题。
我的解决方案(不是我承认的最漂亮的,但我唯一能做的)是手动强制焦点回到 TextField
。您需要两个组件:
- 一个
FocusNode
关联到您的TextField
以收听检查您的TextField
是否从专注变为不专注。如果设置了focusOnNextUnfocus
,在unfocus 后应该重新请求focus
focusOnNextUnfocus
在推送之前设置为true
的布尔值,一旦再次请求焦点,它将设置为 false。
这是对您提供的代码的改编:
import 'package:flutter/material.dart';
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: MyHomePage(title: 'Flutter Demo Home Page'),
);
}
}
class MyHomePage extends StatefulWidget {
MyHomePage({Key? key, required this.title}) : super(key: key);
final String title;
@override
_MyHomePageState createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
/// Handles the focus state of our text field
final focusNode = FocusNode();
/// A bool to keep track on whether we should refocus after
/// unfocus. This will be set to `true` before pushing
var focusOnNextUnfocus = false;
int _counter = 0;
void _incrementCounter() {
setState(() {
_counter++;
});
}
@override
void initState() {
focusNode.addListener(() {
// If we no longer have the focus and should refocus, we refocus
if (!focusNode.hasFocus && focusOnNextUnfocus) {
focusNode.requestFocus();
focusOnNextUnfocus = false; // Reset to false once it has been processed
}
});
super.initState();
}
@override
void dispose() {
focusNode.dispose();
super.dispose();
}
@override
Widget build(BuildContext context) {
late BuildContext anotherContext;
final edit = TextField(
focusNode: focusNode,
onChanged: (String value) async {
if (value.length > 4) {
// Pop does not unfocus so no worries here
Navigator.pop(anotherContext);
} else if (value.length > 3) {
// Push DOES unfocus, so we need to set focusOnNextUnfocus to true
focusOnNextUnfocus = true;
Navigator.of(anotherContext).push(
MaterialPageRoute(builder: (_) {
return Builder(builder: (context) {
return Another();
});
}),
);
}
},
);
final scaffold = MaterialApp(
home: Scaffold(
appBar: AppBar(
title: Text(widget.title),
),
body: Builder(
builder: (context) {
anotherContext = context;
return Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Text(
'You have pushed the button this many times:',
),
Text(
'$_counter',
style: Theme.of(context).textTheme.headline4,
),
],
),
);
},
),
floatingActionButton: FloatingActionButton(
onPressed: _incrementCounter,
tooltip: 'Increment',
child: Icon(Icons.add),
),
),
);
return Scaffold(
body: Stack(
children: [
Positioned(child: scaffold),
Align(
alignment: Alignment.center,
child: Padding(
padding: EdgeInsets.symmetric(horizontal: 16),
child: edit,
),
),
],
),
);
}
}
class Another extends StatelessWidget {
const Another({Key? key}) : super(key: key);
@override
Widget build(BuildContext context) {
return Container(
color: Colors.red,
);
}
}