当焦点在 TextField 上并且在 Flutter 中打开键盘时,如何向上推送内容?
Posted
技术标签:
【中文标题】当焦点在 TextField 上并且在 Flutter 中打开键盘时,如何向上推送内容?【英文标题】:How to push content up when focus is on TextField and keyboard opens in Flutter? 【发布时间】:2022-01-18 16:38:08 【问题描述】:当焦点位于“描述”文本字段并且键盘打开时,我需要将我的内容向上推送
without keyboard
Actual result
Expected result
ListView(
children: [
Column(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text('Title'),
TitleField(
controller: titleEditingController,
),
Text(
'Description',
),
DescriptionField(
focusNode: _focusNode,
controller: descriptionEditingController),
DCDatePicker(),
],
),
AddButton(),
],
),
],
);
【问题讨论】:
【参考方案1】:请参考以下代码
使用 ScrollController 可以在 Description TextField 为 onTapped 和 onFocus 时滚动到底部,方法是添加这段代码
_controller.animateTo(
_controller.position.maxScrollExtent,
duration: Duration(seconds: 1),
curve: Curves.fastOutSlowIn,
);
final _controller = ScrollController();
ListView(
controller: _controller,
children: [
Column(
children: [
Text('Title'),
TitleField(
controller: titleEditingController,
),
Text(
'Description',
),
DescriptionField(
focusNode: _focusNode,
controller: descriptionEditingController),
DCDatePicker(),
],
),
SizedBox(
height: 15.0,
),
AddButton(),
SizedBox(
height: 250.0,
), // Add space at end of list view so it allows to scroll
],
),
请参考以下示例代码
class MainScreen extends StatefulWidget
MainScreen(Key key) : super(key: key);
@override
_MainScreenState createState() => _MainScreenState();
class _MainScreenState extends State<MainScreen>
final TextEditingController emailController = TextEditingController();
final FocusNode emailFocus = FocusNode();
final TextEditingController pswdController = TextEditingController();
final FocusNode pswdFocus = FocusNode();
final _validationKey = GlobalKey<FormState>();
@override
void initState()
super.initState();
@override
void dispose()
super.dispose();
int validateEmail(String emailAddress)
String patttern = r'^[\w-\.]+@([\w-]+\.)+[\w-]2,4$';
RegExp regExp = new RegExp(patttern);
if (emailAddress.isEmpty || emailAddress.length == 0)
return 1;
else if (!regExp.hasMatch(emailAddress))
return 2;
else
return 0;
int validatePassword(String pswd)
if (pswd.isEmpty || pswd.length == 0)
return 1;
else if (pswd != null && pswd.isNotEmpty && pswd.length <= 8)
return 2;
else
return 0;
final _controller = ScrollController();
@override
Widget build(BuildContext context)
return Scaffold(
appBar: AppBar(
backgroundColor: Colors.lightBlue,
automaticallyImplyLeading: true,
leading: Icon(
Icons.arrow_back,
),
title: Text("Example"),
centerTitle: true,
),
body: Container(
padding: EdgeInsets.all(15.0),
child: ListView(
controller: _controller,
children: [
Form(
key: _validationKey,
child: Column(
children: [
/* Email */
TextFormField(
autovalidateMode: AutovalidateMode.onUserInteraction,
/* autovalidate is disabled */
controller: emailController,
keyboardType: TextInputType.emailAddress,
onChanged: (val) ,
maxLines: 1,
validator: (value)
int res = validateEmail(value);
if (res == 1)
return "Please fill email address";
else if (res == 2)
return "Please enter valid email address";
else
return null;
,
focusNode: emailFocus,
autofocus: false,
decoration: InputDecoration(
errorMaxLines: 3,
counterText: "",
filled: true,
fillColor: Colors.white,
focusedBorder: OutlineInputBorder(
borderRadius: BorderRadius.all(Radius.circular(4)),
borderSide: BorderSide(
width: 1,
color: Color(0xffE5E5E5),
),
),
disabledBorder: OutlineInputBorder(
borderRadius: BorderRadius.all(Radius.circular(4)),
borderSide: BorderSide(
width: 1,
color: Color(0xffE5E5E5),
),
),
enabledBorder: OutlineInputBorder(
borderRadius: BorderRadius.all(Radius.circular(4)),
borderSide: BorderSide(
width: 1,
color: Color(0xffE5E5E5),
),
),
border: OutlineInputBorder(
borderRadius: BorderRadius.all(Radius.circular(4)),
borderSide: BorderSide(
width: 1,
),
),
errorBorder: OutlineInputBorder(
borderRadius: BorderRadius.all(Radius.circular(4)),
borderSide: BorderSide(
width: 1,
color: Colors.red,
)),
focusedErrorBorder: OutlineInputBorder(
borderRadius: BorderRadius.all(Radius.circular(4)),
borderSide: BorderSide(
width: 1,
color: Colors.red,
),
),
hintText: "Enter email address" ?? "",
),
),
SizedBox(
height: 15.0,
),
/* Password */
TextFormField(
autovalidateMode: AutovalidateMode.onUserInteraction,
/* autovalidate is disabled */
controller: pswdController,
inputFormatters: [
FilteringTextInputFormatter.deny(RegExp(r"\s\s")),
FilteringTextInputFormatter.deny(RegExp(
r'(\u00a9|\u00ae|[\u2000-\u3300]|\ud83c[\ud000-\udfff]|\ud83d[\ud000-\udfff]|\ud83e[\ud000-\udfff])')),
],
keyboardType: TextInputType.text,
onChanged: (val) ,
maxLines: 15,
validator: (value)
int res = validatePassword(value);
if (res == 1)
return "Please enter password";
else if (res == 2)
return "Please enter minimum 9 characters";
else
return null;
,
focusNode: pswdFocus,
autofocus: false,
onTap: ()
_controller.animateTo(
_controller.position.maxScrollExtent,
duration: Duration(seconds: 1),
curve: Curves.fastOutSlowIn,
);
,
decoration: InputDecoration(
errorMaxLines: 3,
counterText: "",
filled: true,
fillColor: Colors.white,
focusedBorder: OutlineInputBorder(
borderRadius: BorderRadius.all(Radius.circular(4)),
borderSide: BorderSide(
width: 1,
color: Color(0xffE5E5E5),
),
),
disabledBorder: OutlineInputBorder(
borderRadius: BorderRadius.all(Radius.circular(4)),
borderSide: BorderSide(
width: 1,
color: Color(0xffE5E5E5),
),
),
enabledBorder: OutlineInputBorder(
borderRadius: BorderRadius.all(Radius.circular(4)),
borderSide: BorderSide(
width: 1,
color: Color(0xffE5E5E5),
),
),
border: OutlineInputBorder(
borderRadius: BorderRadius.all(Radius.circular(4)),
borderSide: BorderSide(
width: 1,
),
),
errorBorder: OutlineInputBorder(
borderRadius: BorderRadius.all(Radius.circular(4)),
borderSide: BorderSide(
width: 1,
color: Colors.red,
)),
focusedErrorBorder: OutlineInputBorder(
borderRadius: BorderRadius.all(Radius.circular(4)),
borderSide: BorderSide(
width: 1,
color: Colors.red,
),
),
hintText: "Enter password" ?? "",
),
),
],
),
),
SizedBox(
height: 15.0,
),
OutlinedButton(
onPressed: ()
_validationKey.currentState.validate();
if (emailController.text.isEmpty)
emailFocus.requestFocus();
else if (pswdController.text.isEmpty ||
pswdController.text.length <= 8)
pswdFocus.requestFocus();
_controller.animateTo(
_controller.position.maxScrollExtent,
duration: Duration(seconds: 1),
curve: Curves.fastOutSlowIn,
);
,
child: Text("Validate"),
),
SizedBox(
height: 250.0,
),
],
),
),
);
【讨论】:
谢谢,这个解决方案有效,但在我的情况下,当我点击文本字段两次时,它会滚动到最后。我使用 onTap,而不是 onDoubleTap 如果您在列表视图的末尾使用了尺寸大小的框,您是否添加了带有高度的尺寸框尝试降低高度并检查以上是关于当焦点在 TextField 上并且在 Flutter 中打开键盘时,如何向上推送内容?的主要内容,如果未能解决你的问题,请参考以下文章
当应用程序启动时有两种状态时将焦点设置在 TextField 上
当initialValues通过\绑定到props.object时,如何使用Formik表单将焦点设置在TextField\input上?