如何使具有自定义FocusNode的TextField失去焦点?

时间:2018-11-26 12:36:35

标签: dart flutter

我知道不专心的一般答案是使用这段代码:FocusScope.of(context).requestFocus(new FocusNode());

但是当TextField具有自定义focusNode时,此代码似乎无效。

SystemChannels.textInput.invokeMethod('TextInput.hide');仍然有效,但是只能移除键盘-字段本身仍处于选中状态。

代码(删除了不相关的部分):

class RegisterScreen extends StatelessWidget {
  final phoneNumberTEC = TextEditingController();
  final passwordTEC = TextEditingController();
  final passwordFocusNode = FocusNode();

  @override
  Widget build(BuildContext context) {
    return this.keyboardDismisser(
      context: context,
      child: Scaffold(
        appBar: new AppBar(
          title: new Text("Register"),
        ),
        body: this.page(context),
        resizeToAvoidBottomPadding: false,
      ),
    );
  }

  Widget keyboardDismisser({BuildContext context, Widget child}) {
    final gesture = GestureDetector(
      onTap: () {
        this.passwordFocusNode.unfocus();
        FocusScope.of(context).requestFocus(new FocusNode());
        SystemChannels.textInput.invokeMethod('TextInput.hide');
      },
      child: child,
    );
    return gesture;
  }

  Widget page(BuildContext context) {
    return Column(
        mainAxisAlignment: MainAxisAlignment.spaceBetween,
        children: <Widget>[
          Container(
            padding: new EdgeInsets.all(16.0),
            child: Column(
                mainAxisAlignment: MainAxisAlignment.center,
                crossAxisAlignment: CrossAxisAlignment.center,
                children: <Widget>[
                  this.phoneNumberTextField(context),
                  this.passwordTextField(context),
                ]
            ),
          ),
          // cutting irrelevant widgets out
          )
        ]
    );
  }

  Widget phoneNumberTextField(BuildContext context) {
    return TextField(
      controller: this.phoneNumberTEC,
      decoration: InputDecoration(hintText: "Phone number"),
      onSubmitted: (string) {
        FocusScope.of(context).requestFocus(this.passwordFocusNode);
      },
    );
  }

  Widget passwordTextField(BuildContext context) {
    return TextField(
      controller: this.passwordTEC,
      decoration: InputDecoration(hintText: "Password"),
      obscureText: true,
      focusNode: this.passwordFocusNode,
      onSubmitted: (string) {
        this.performRegister(context);
      },
    );
  }

}

8 个答案:

答案 0 :(得分:36)

这里的答案与@kasiara的答案类似,只是另一种方式。

FocusScope.of(context).unfocus();
_textEditingController.clear();

答案 1 :(得分:5)

这里适用于新的 Flutter 版本:

import 'package:flutter/material.dart';

void main() {  
  runApp(MyApp());
}

class MyApp extends StatelessWidget {
  // This widget is the root of your application.
  @override
  Widget build(BuildContext context) {
    return Listener(
      onPointerDown: (_) {
        FocusScopeNode currentFocus = FocusScope.of(context);
        if (!currentFocus.hasPrimaryFocus) {
          currentFocus.focusedChild?.unfocus();
        }
      },
      child: MaterialApp(
        title: 'Flutter Demo',
        home: Scaffold(body: SafeArea(child: TextField())),
      ),
    );
  }
}

答案 2 :(得分:4)

您可能已经看到有些人使用这种方法:

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

在这种方法中,您是动态创建一个 FocusNode 而不是处理它。虽然这也有效,但不建议这样做,因为 FocusNode 是持久性对象,您应该处理它们以避免内存泄漏:

@override
  void dispose() {
    focusNode.dispose();
    super.dispose();
    }

看看这个link。作者对如何以最佳和正确的方式做到这一点有很好的解释。祝你有美好的一天:)

答案 3 :(得分:3)

与@Blasanka相似,但更短。 将其放在包装整个页面的GestureDetector中。

Joiner

答案 4 :(得分:2)

在我的情况下,我有一个Private Sub Workbook_Open() Dim ws As Worksheet For Each ws In ThisWorkbook.Sheets With ws If .Range("W6").Value = 0 Then HideFG ws Else HideF ws End If End With Next End Sub Sub HideF(wsht As Worksheet) ' ' HideF Macro ' ' For i = 1 To wsht.Shapes.Count wsht.Shapes(i).Visible = msoTrue Next i wsht.Shapes.Range(Array("F")).Visible = msoFalse Application.CommandBars("Selection").Visible = False End Sub Sub HideFG(wsht As Worksheet) ' ' HideFG Macro ' ' For i = 1 To wsht.Shapes.Count wsht.Shapes(i).Visible = msoTrue Next i wsht.Shapes.Range(Array("FG")).Visible = msoFalse Application.CommandBars("Selection").Visible = False End Sub ,我想从中移开焦点并在可能的情况下隐藏键盘。下面的代码可以同时清除TextField的内容。

TextFormField

其中 _textEditingController 只是处于窗口小部件状态的FocusScope.of(context).requestFocus(new FocusNode()); //remove focus WidgetsBinding.instance.addPostFrameCallback((_) => _textEditingController.clear()); // clear content

答案 5 :(得分:2)

用 GestureDetector Widget 包裹页面 Root Widget。这对我有用

     @override
  Widget build(BuildContext context) {
    return GestureDetector(
      onTap: () {
      FocusScope.of(context).unfocus();
      new TextEditingController().clear();
    },
      child: _yourPageRootWidget(..)
)

}

答案 6 :(得分:0)

出来,我没有正确管理FocusNode的生命周期:https://flutter.io/docs/cookbook/forms/focus

因此,以下代码确实对我有用:

class RegisterScreen extends StatefulWidget {
  @override
  _RegisterScreenState createState() => _RegisterScreenState();
}

class _RegisterScreenState extends State<RegisterScreen> {
  final phoneNumberTEC = TextEditingController();
  final passwordTEC = TextEditingController();
  FocusNode passwordFocusNode;

  @override
  void initState() {
    super.initState();

    this.passwordFocusNode = FocusNode();
  }

  @override
  void dispose() {
    this.passwordFocusNode.dispose();

    super.dispose();
  }

  @override
  Widget build(BuildContext context) {
    return this.keyboardDismisser(
      context: context,
      child: Scaffold(
        appBar: new AppBar(
          title: new Text("Register"),
        ),
        body: this.page(context),
        resizeToAvoidBottomPadding: false,
      ),
    );
  }

  Widget keyboardDismisser({BuildContext context, Widget child}) {
    final gesture = GestureDetector(
      onTap: () {
        FocusScope.of(context).requestFocus(new FocusNode());
        debugPrint("!!!");
      },
      child: child,
    );
    return gesture;
  }

// ...

}

感谢@SnakeyHips的帮助-当问题可以在我的身边重现时,无法重现该问题,这给了我一些想法:)

答案 7 :(得分:0)

@override
Widget build(BuildContext context) {
FocusScopeNode currentFocus = FocusScope.of(context);
if (!currentFocus.hasPrimaryFocus) {
currentFocus.unfocus();
}
return Material(
child: Scaffold(

仅添加新功能(页面)标题,(返回主屏幕自动关闭键盘)