英文:
Flutter Android/IOS - Dynamic list with TextInputAction.next not behaving as expected
问题
我有一个包含TextFormFields的动态列表。我已经添加了一个textInputAction
,将其值设置为TextInputAction.next
,所以点击下一个时它会移动到下一个字段。在页面底部,我添加了一个点击完成的按钮。应用的Scaffold
的resizeToAvoidBottomInset
设置为true
,所以TextFields在到达底部时会滚动。
按钮需要放在可滚动区域之外,这样它就始终可见在底部。
问题是当我点击下一个时,键盘在达到按钮时关闭,这不是预期的行为。
当我添加了一个15的Padding时,在我的手机上问题得到了解决,但在其他设备上没有,所以这不是一个有效的解决方案。
我创建了一个示例项目,在我的手机(三星S22)上它不起作用:
import 'package:flutter/material.dart';
void main() {
runApp(const MyApp());
}
class MyApp extends StatelessWidget {
const MyApp({Key? key});
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(
colorScheme: ColorScheme.fromSwatch(primarySwatch: Colors.deepPurple),
useMaterial3: true,
),
home: const MyHomePage(title: 'Flutter Demo Home Page'),
);
}
}
class MyHomePage extends StatefulWidget {
const MyHomePage({Key? key, required this.title});
final String title;
@override
State<MyHomePage> createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
backgroundColor: Theme.of(context).colorScheme.secondary,
title: Text(widget.title),
),
body: const ItemList(),
);
}
}
class ItemList extends StatefulWidget {
const ItemList({Key? key});
@override
State<ItemList> createState() => _ItemListState();
}
class _ItemListState extends State<ItemList> {
final _formKey = GlobalKey<FormState>();
final List<String> items = [];
@override
void initState() {
items.addAll(List<String>.generate(20, (int index) => 'String$index',
growable: true));
super.initState();
}
@override
Widget build(BuildContext context) {
return Column(
children: [
Expanded(
child: SingleChildScrollView(
child: Column(
children: [
const Row(
children: [
Text('Title: '),
Text('Value'),
],
),
Form(
key: _formKey,
child: ListView.builder(
scrollDirection: Axis.vertical,
shrinkWrap: true,
physics: const NeverScrollableScrollPhysics(),
itemCount: items.length,
itemBuilder: (context, index) {
final item = items[index];
final bool isLast = items.length - 1 == index;
return Row(
children: [
Text(item),
const SizedBox(
width: 20,
),
Expanded(
child: TextFormField(
onTapOutside: (_) =>
FocusManager.instance.primaryFocus?.unfocus(),
textInputAction: isLast
? TextInputAction.done
: TextInputAction.next,
decoration: const InputDecoration(
isDense: true,
),
),
),
],
);
},
),
),
],
),
),
),
Align(
alignment: Alignment.bottomCenter,
child: Padding(
padding: const EdgeInsets.all(15.0),
child: ElevatedButton(
onPressed: () {},
child: const SizedBox(
height: 40,
child: Center(
child: Text('Finish'),
),
),
),
),
),
],
);
}
}
英文:
I have a dynamic list containing TextFormFields. I've added a textInputAction
with TextInputAction.next
as the value, so it will move to the next field upon clicking next. At the bottom of the page, I've added a button to click finish. The app Scaffold
has the resizeToAvoidBottomInset
set to true
, so the TextFields scroll upon reaching the bottom.
The button needs to be outside of the ScrollableView so it's always visible at the bottom.
The issue is that when I click next, the keyboard closes when reaching the button, which is not intended behavior.
Also when I add a Padding of 15 the issue is resolved on my phone but not others, so that is not a valid solution.
I've created a sample project where on my phone (Samsung S22) it doesn't work:
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'),
);
}
}
class MyHomePage extends StatefulWidget {
const MyHomePage({super.key, required this.title});
final String title;
@override
State<MyHomePage> createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
backgroundColor: Theme.of(context).colorScheme.inversePrimary,
title: Text(widget.title),
),
body: const ItemList(),
);
}
}
class ItemList extends StatefulWidget {
const ItemList({
super.key,
});
@override
State<ItemList> createState() => _ItemListState();
}
class _ItemListState extends State<ItemList> {
final _formKey = GlobalKey<FormState>();
final List<String> items = [];
@override
void initState() {
items.addAll(List<String>.generate(20, (int index) => 'String$index',
growable: true));
super.initState();
}
@override
Widget build(BuildContext context) {
return Column(
children: [
Expanded(
child: SingleChildScrollView(
child: Column(
children: [
const Row(
children: [
Text('Title: '),
Text('Value'),
],
),
Form(
key: _formKey,
child: ListView.builder(
scrollDirection: Axis.vertical,
shrinkWrap: true,
physics: const NeverScrollableScrollPhysics(),
itemCount: items.length,
itemBuilder: (context, index) {
final item = items[index];
final bool isLast = items.length - 1 == index;
return Row(
children: [
Text(item),
const SizedBox(
width: 20,
),
Expanded(
child: TextFormField(
onTapOutside: (_) =>
FocusManager.instance.primaryFocus?.unfocus(),
textInputAction: isLast
? TextInputAction.done
: TextInputAction.next,
decoration: const InputDecoration(
isDense: true,
),
),
),
],
);
},
),
),
],
),
),
),
Align(
alignment: Alignment.bottomLeft,
child: Padding(
padding: const EdgeInsets.all(15.0),
child: ElevatedButton(
onPressed: () {},
child: const SizedBox(
height: 40,
child: Center(
child: Text('Finish'),
),
),
),
),
),
],
);
}
}
- I've tried adding a Stack and placing the button behind the List.
- I've placed
resizeToAvoidBottomInset
onfalse
but the page didn't scroll to my TextFormField anymore. - I've added a padding but that only works for my screen size.
Any help would be appreciated 🙂.
答案1
得分: 0
我在github上找到了解决方案。我只需要将以下内容添加到按钮中:
ElevatedButton(
focusNode: FocusNode(skipTraversal: true), //new line
onPressed: () {},
child: const SizedBox(
height: 40,
child: Center(
child: Text('完成'),
),
),
)
英文:
I found the solution on github. I only needed to add the following to the button:
ElevatedButton(
focusNode: FocusNode(skipTraversal: true), //new line
onPressed: () {},
child: const SizedBox(
height: 40,
child: Center(
child: Text('Finish'),
),
),
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论