简体   繁体   English

FocusNode - 为什么 requestFocus() 不起作用?

[英]FocusNode - Why is requestFocus() not working?

The following is the relevant code.以下是相关代码。 The debugPrint() in the onFieldSubmitted: is running, so the code is getting here, but the focus is not changing. onFieldSubmitted: 中的 debugPrint() 正在运行,所以代码到了这里,但焦点没有改变。 Focus does not change.焦点不变。

 _createItemHeadingWidget() {
    return Padding(
      padding: const EdgeInsets.all(8.0),
      child: TextFormField(
        controller: _controllerItemHed,
        autofocus: true,
        focusNode: _focusNodeItemHed,
        textInputAction: TextInputAction.next,
        onFieldSubmitted: (v) {
          debugPrint("ItemHeading submitted");
          FocusScope.of(context).requestFocus(_focusNodeItemDetail);
        },
        decoration: InputDecoration(
          labelText: "Item Heading",
          hintText: "Enter item heading",
          border: OutlineInputBorder(borderRadius: BorderRadius.circular(20.0)),
        ),
      ),
    );
  }
  Widget _createItemDetailWidget() {
    return Padding(
      padding: const EdgeInsets.all(8.0),
      child: TextFormField(
        controller: _controllerItemDetail,
        maxLength: 75,
        focusNode: _focusNodeItemDetail,
        textInputAction: TextInputAction.next,
        onFieldSubmitted: (v) {
          debugPrint("ItemDetail submitted");
          FocusScope.of(context).requestFocus(_focusNodeItemPrice);
        },
        decoration: InputDecoration(
          labelText: "Item Detail",
          hintText: "Enter item detail",
          border: OutlineInputBorder(borderRadius: BorderRadius.circular(20.0)),
        ),
      ),
    );
  }
class DataEntryState extends State<DataEntry> {
  final TextEditingController _controllerItemHed = TextEditingController();
  final TextEditingController _controllerItemDetail = TextEditingController();
  final TextEditingController _controllerItemPrice = TextEditingController();
  final TextEditingController _controllerSeller = TextEditingController();
  final TextEditingController _controllerContactNr = TextEditingController();
  final TextEditingController _controllerLocation = TextEditingController();

  final FocusNode _focusNodeItemHed = FocusNode();
  final FocusNode _focusNodeItemDetail = FocusNode();
  final FocusNode _focusNodeItemPrice = FocusNode();
  final FocusNode _focusNodeSeller = FocusNode();
  final FocusNode _focusNodeContactNr = FocusNode();
  final FocusNode _focusNodeLocation = FocusNode();

After trying many things that did not work, the only solution that I could find is as follows:在尝试了许多不起作用的事情后,我能找到的唯一解决方案如下:

  _changeFocus(BuildContext context, FocusNode focusNodeCurrent,
      FocusNode focusNodeNext) {
    focusNodeCurrent.unfocus();
    setState(() => _focusNodeCurrent = focusNodeNext);
  }

debugPrint() showed that in _changeFocus(), unfocus() does work, and that requestFocus() did not work. debugPrint() 显示在 _changeFocus() 中, unfocus() 确实有效,而 requestFocus() 无效。

In the build :在构建中:

    if (_focusNodeCurrent != null)
      FocusScope.of(context).requestFocus(_focusNodeCurrent);

Other relevant code (some of which is probably redundant) :其他相关代码(其中一些可能是多余的):

 TextFormField _createItemHeadingWidget(BuildContext context) {
    FocusScope.of(context).reparentIfNeeded(_focusNodeItemHed);
    return TextFormField(
      controller: _controllerItemHed,
      maxLength: 50,
      keyboardType: TextInputType.text,
      autofocus: _dataRec == null,
      focusNode: _focusNodeItemHed,
      textInputAction: TextInputAction.next,
      onFieldSubmitted: (v) {
        _changeFocus(context, _focusNodeItemHed, _focusNodeItemDetail);
      },
      decoration: InputDecoration(
        labelText: "Item Heading",
        hintText: "Enter item heading",
        border: OutlineInputBorder(borderRadius: BorderRadius.circular(20.0)),
      ),
    );
  }
firstFieldFocusNode.nextFocus();

对我有用

Doing setState() to solve this problem didn't seem to me like the optimum solution, so I kept testing.用 setState() 来解决这个问题在我看来并不是最佳解决方案,所以我一直在测试。 After a lot of further testing which mainly involved removing everything that I could from the app, I eventually replaced the creation of MaterialApp with creation of Scaffold.经过大量进一步的测试,主要涉及从应用程序中删除我可以删除的所有内容,我最终将 MaterialApp 的创建替换为 Scaffold 的创建。 This fixed the problem.这解决了问题。 Now it appears to work as intended.现在它似乎按预期工作。 All that is required is to do is:所需要做的就是:

 _changeFocus(BuildContext context, FocusNode focusNodeNew) {
    FocusScope.of(context).requestFocus(focusNodeNew);
  }

I presume that the reason I was initially creating a MaterialApp is that I copied that from another app when I was initially starting to learn Flutter.我认为我最初创建 MaterialApp 的原因是我最初开始学习 Flutter 时从另一个应用程序复制了它。 It appears that it's not necessary to create a MaterialApp, but I don't know the reasons for creating a MaterialApp as opposed to creating just the Scaffold.似乎没有必要创建一个MaterialApp,但我不知道创建一个MaterialApp而不是只创建Scaffold的原因。

Whether it is a bug in flutter that causes this behavior, I don't know.是否是flutter中的一个bug导致了这种行为,我不知道。 It may be just a "feature" of using MaterialApp, or perhaps I was misusing MaterialApp.它可能只是使用 MaterialApp 的一个“功能”,或者我可能误用了 MaterialApp。

这是很好的解释,说明颤振中的焦点是如何工作的: https//flutter.dev/docs/cookbook/forms/focus

For anyone else struggling with this I was just playing around and made a demo.对于其他为此而苦苦挣扎的人,我只是在玩弄并制作了一个演示。

在此处输入图片说明

You can switch the focus to the left or right textfields or cancel the focus.您可以将焦点切换到左侧或右侧文本字段或取消焦点。 The code below is a combination of @Brian Oh 's answers and some new code.下面的代码是@Brian Oh 的答案和一些新代码的组合。 Features:特征:

  • keeps track of all nodes including no focus and current focus跟踪所有节点,包括无焦点和当前焦点
  • changeFocus function only requires nextFocus parameter, doesn't use FocusScope.of(context).requestFocus(_nextFocusNode) and doesn't have to set state changeFocus 函数只需要 nextFocus 参数,不使用FocusScope.of(context).requestFocus(_nextFocusNode)并且不必设置状态
import 'package:flutter/material.dart';

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

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(home: Home(),);
  }
}

class Home extends StatefulWidget {
  @override
  HomeState createState() => HomeState();
}

class HomeState extends State<Home> {

  FocusNode currentFocusNode;
  FocusNode leftFocusNode;
  FocusNode rightFocusNode;
  FocusNode noFocusNode;

  @override
  void initState() {
    super.initState();
    currentFocusNode = FocusNode();
    leftFocusNode = FocusNode();
    rightFocusNode = FocusNode();
    noFocusNode = FocusNode();
  }

  @override
  void dispose() {
    //currentFocusNode.dispose();
    //leftFocusNode.dispose();
    //rightFocusNode.dispose();
    //noFocusNode.dispose();
    super.dispose();
  }

  changeFocus(FocusNode focusNodeNext) {
    currentFocusNode.unfocus();
    focusNodeNext.requestFocus();
    currentFocusNode = focusNodeNext;
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: Padding(
        padding: const EdgeInsets.fromLTRB(0, 40, 0, 0),
        child: Row(
          mainAxisAlignment: MainAxisAlignment.center,
          crossAxisAlignment: CrossAxisAlignment.start,
          children: [

            Column(
              children: <Widget>[
                Container( width: 50, child: TextField(
                  focusNode: leftFocusNode,
                ),),
                RaisedButton(
                  child: Text('^ Focus ^'),
                  onPressed: () => changeFocus(leftFocusNode),
                ),
              ],
            ),

            Column(
              children: <Widget>[
                Container( width: 50, child: TextField(
                  focusNode: rightFocusNode,
                ),),
                RaisedButton(
                  child: Text('^ Focus ^'),
                  onPressed: () => changeFocus(rightFocusNode),
                ),
              ],
            ),

            RaisedButton(
              child: Text('  Cancel Focus'),
              onPressed: () => changeFocus(noFocusNode),
            ),

          ],
        ),
      ),
    );
  }
}

EDIT:编辑:

I used this code in another app and got an error我在另一个应用程序中使用了此代码并出现错误

A FocusNode was used after being disposed.一个FocusNode被销毁后使用。

according to this github link you should't call dispose.根据这个 github 链接,你不应该调用 dispose。 I've commented out the dispose calls made to focus nodes above and the error disappeared.我已经注释掉了上面对焦点节点的处理调用,错误消失了。

Use

FocusScope.of(context).unfocus();

instead of代替

FocusScope.of(context).requestFocus(new FocusNode());

The following is the relevant code.以下是相关代码。 The debugPrint() in the onFieldSubmitted: is running, so the code is getting here, but the focus is not changing. onFieldSubmitted:中的debugPrint()正在运行,因此代码在此处,但是焦点没有改变。 Focus does not change.重点不会改变。

 _createItemHeadingWidget() {
    return Padding(
      padding: const EdgeInsets.all(8.0),
      child: TextFormField(
        controller: _controllerItemHed,
        autofocus: true,
        focusNode: _focusNodeItemHed,
        textInputAction: TextInputAction.next,
        onFieldSubmitted: (v) {
          debugPrint("ItemHeading submitted");
          FocusScope.of(context).requestFocus(_focusNodeItemDetail);
        },
        decoration: InputDecoration(
          labelText: "Item Heading",
          hintText: "Enter item heading",
          border: OutlineInputBorder(borderRadius: BorderRadius.circular(20.0)),
        ),
      ),
    );
  }
  Widget _createItemDetailWidget() {
    return Padding(
      padding: const EdgeInsets.all(8.0),
      child: TextFormField(
        controller: _controllerItemDetail,
        maxLength: 75,
        focusNode: _focusNodeItemDetail,
        textInputAction: TextInputAction.next,
        onFieldSubmitted: (v) {
          debugPrint("ItemDetail submitted");
          FocusScope.of(context).requestFocus(_focusNodeItemPrice);
        },
        decoration: InputDecoration(
          labelText: "Item Detail",
          hintText: "Enter item detail",
          border: OutlineInputBorder(borderRadius: BorderRadius.circular(20.0)),
        ),
      ),
    );
  }
class DataEntryState extends State<DataEntry> {
  final TextEditingController _controllerItemHed = TextEditingController();
  final TextEditingController _controllerItemDetail = TextEditingController();
  final TextEditingController _controllerItemPrice = TextEditingController();
  final TextEditingController _controllerSeller = TextEditingController();
  final TextEditingController _controllerContactNr = TextEditingController();
  final TextEditingController _controllerLocation = TextEditingController();

  final FocusNode _focusNodeItemHed = FocusNode();
  final FocusNode _focusNodeItemDetail = FocusNode();
  final FocusNode _focusNodeItemPrice = FocusNode();
  final FocusNode _focusNodeSeller = FocusNode();
  final FocusNode _focusNodeContactNr = FocusNode();
  final FocusNode _focusNodeLocation = FocusNode();

Using FocusScope.of(context).nextFocus() has worked for me使用FocusScope.of(context).nextFocus()对我FocusScope.of(context).nextFocus()

Custom Widget Code I Used我使用的自定义小部件代码

CupertinoTextFormFieldRow customTextField(
  String pretext, String supportText,
  TextEditingController controller, Function(String) validatorFun) {
  return CupertinoTextFormFieldRow(
    controller: controller,
    prefix: Text(pretext),
    placeholder: supportText,
    validator: (val) => validatorFun(val!),
    textInputAction: TextInputAction.next,
    onEditingComplete: () {
      FocusScope.of(context).nextFocus();
    },
  );
}```

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM