flutter 如何将焦点从一个文本字段平滑地移动到一个新创建的文本字段?

flseospp  于 2023-01-31  发布在  Flutter
关注(0)|答案(1)|浏览(136)

我想创建一个屏幕,其中许多TextFIeld垂直排列,在编辑底部TextField时按Enter键,一个新的TextField被添加在它下面移动焦点太多。我创建了一个演示应用程序参考的例子在docs的FocusNode和它的工作基本上,但键盘反弹时,移动焦点到一个新创建的TextField(请参阅下面的gif)。如何修复此不需要的行为?
The gif of the demo app
演示应用程序的代码如下:

import 'package:flutter/material.dart';

void main() => runApp(const MyApp());

class MyApp extends StatelessWidget {
  const MyApp({super.key});

  static const String _title = 'Flutter Code Sample';

  @override
  Widget build(BuildContext context) {
    return const MaterialApp(
      title: _title,
      home: MyStatefulWidget(),
    );
  }
}

class MyStatefulWidget extends StatefulWidget {
  const MyStatefulWidget({super.key});

  @override
  State<MyStatefulWidget> createState() => _MyStatefulWidgetState();
}

class _MyStatefulWidgetState extends State<MyStatefulWidget> {
  int focusedChild = 0;
  List<Widget> children = <Widget>[];
  List<FocusNode> childFocusNodes = <FocusNode>[];

  @override
  void initState() {
    super.initState();
    // Add the first child.
    _addChild();
  }

  @override
  void dispose() {
    for (final FocusNode node in childFocusNodes) {
      node.dispose();
    }
    super.dispose();
  }

  void _addChild() {
    // Calling requestFocus here creates a deferred request for focus, since the
    // node is not yet part of the focus tree.
    childFocusNodes
        .add(FocusNode(debugLabel: 'Child ${children.length}')..requestFocus());

    children.add(
      TextField(
        focusNode: childFocusNodes.last,
        textInputAction: TextInputAction.unspecified,
        minLines: 1,
        onSubmitted: (value) {
          setState(() {
            focusedChild = children.length;
            _addChild();
          });
        },
      ),
    );
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: SafeArea(
        child: SingleChildScrollView(
          child: Column(
            children: children,
          ),
        ),
      ),
    );
  }
}
tkclm6bt

tkclm6bt1#

Screenshot
您需要使用TextInputAction
TextInputAction.next:将焦点移动到下一个可聚焦项目。
TextInputAction.done:关闭键盘。

class TestWidget extends StatelessWidget {
  const TestWidget({super.key});

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: SafeArea(
        child: Column(
          mainAxisAlignment: MainAxisAlignment.end,
          children: const [
            TextField(
              decoration: InputDecoration(hintText: 'TextField #1 with next'),
              textInputAction: TextInputAction.next, // Moves the focus to the next focusable item.
            ),
            TextField(
              decoration: InputDecoration(hintText: 'TextField #2 with next'),
              textInputAction: TextInputAction.next, // Moves the focus to the next focusable item.
            ),
            TextField(
              decoration: InputDecoration(hintText: 'TextField #3 with done'),
              textInputAction: TextInputAction.done, // Close the keyboard.
            ),
          ],
        ),
      ),
    );
  }
}

更新

在编辑完成时创建新文本字段,并将焦点更改为新文本字段。

1.您需要使用onEditingComplete函数,而不是onSubmitted。因为onEditingComplete不会关闭(解散)键盘。
1.我重写了你的代码,删除了生成窗口小部件列表的操作,并将其替换为TextEditingController,因为将UI(窗口小部件)保存在变量中是一种糟糕的体验。因此,文本字段按TextEditingController长度生成。
1.我删除了FocusNode列表,并使用FocusScope.of(context).nextFocus()更改焦点。
1.创建新的TextEditingController函数调用后,nextFocus()延迟,以便有时间重新创建新UI。

  • 这里是完整的代码:*
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(home: MyStatefulWidget());
  }
}

class MyStatefulWidget extends StatefulWidget {
  const MyStatefulWidget({super.key});

  @override
  State<MyStatefulWidget> createState() => _MyStatefulWidgetState();
}

class _MyStatefulWidgetState extends State<MyStatefulWidget> {
  final List<TextEditingController> _controllers = [
    TextEditingController()
  ]; // with first controller

  _addController() {
    setState(() {
      _controllers.add(TextEditingController());
    });

    Future.delayed(const Duration(milliseconds: 100), () {
      // Add delay for recreate UI after setState
      FocusScope.of(context).nextFocus();
    });
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: SafeArea(
        child: SingleChildScrollView(
          child: Column(
            children: _controllers
                .map((e) => TextField(
                      textInputAction: TextInputAction.next,
                      controller: e,
                      onEditingComplete: _addController,
                    ))
                .toList(),
          ),
        ),
      ),
    );
  }
}

相关问题