Flutter Android/IOS – Dynamic list with TextInputAction.next not behaving as expected

huangapple go评论70阅读模式
英文:

Flutter Android/IOS - Dynamic list with TextInputAction.next not behaving as expected

问题

我有一个包含TextFormFields的动态列表。我已经添加了一个textInputAction,将其值设置为TextInputAction.next,所以点击下一个时它会移动到下一个字段。在页面底部,我添加了一个点击完成的按钮。应用的ScaffoldresizeToAvoidBottomInset设置为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 &#39;package:flutter/material.dart&#39;;
void main() {
runApp(const MyApp());
}
class MyApp extends StatelessWidget {
const MyApp({super.key});
@override
Widget build(BuildContext context) {
return MaterialApp(
title: &#39;Flutter Demo&#39;,
theme: ThemeData(
colorScheme: ColorScheme.fromSeed(seedColor: Colors.deepPurple),
useMaterial3: true,
),
home: const MyHomePage(title: &#39;Flutter Demo Home Page&#39;),
);
}
}
class MyHomePage extends StatefulWidget {
const MyHomePage({super.key, required this.title});
final String title;
@override
State&lt;MyHomePage&gt; createState() =&gt; _MyHomePageState();
}
class _MyHomePageState extends State&lt;MyHomePage&gt; {
@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&lt;ItemList&gt; createState() =&gt; _ItemListState();
}
class _ItemListState extends State&lt;ItemList&gt; {
final _formKey = GlobalKey&lt;FormState&gt;();
final List&lt;String&gt; items = [];
@override
void initState() {
items.addAll(List&lt;String&gt;.generate(20, (int index) =&gt; &#39;String$index&#39;,
growable: true));
super.initState();
}
@override
Widget build(BuildContext context) {
return Column(
children: [
Expanded(
child: SingleChildScrollView(
child: Column(
children: [
const Row(
children: [
Text(&#39;Title: &#39;),
Text(&#39;Value&#39;),
],
),
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: (_) =&gt;
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(&#39;Finish&#39;),
),
),
),
),
),
],
);
}
}
  1. I've tried adding a Stack and placing the button behind the List.
  2. I've placed resizeToAvoidBottomInset on false but the page didn't scroll to my TextFormField anymore.
  3. 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(&#39;Finish&#39;),
),
),

huangapple
  • 本文由 发表于 2023年3月7日 16:42:03
  • 转载请务必保留本文链接:https://go.coder-hub.com/75659666.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定