单击TextField /屏幕外的任何地方后,如何在颤动时隐藏软输入键盘?

Amm*_*ang 23 dart flutter

目前我知道使用此代码隐藏软键盘的onTap方法,通过任何小部件的方法.

FocusScope.of(context).requestFocus(new FocusNode());
Run Code Online (Sandbox Code Playgroud)

但我想通过单击TextField外部或屏幕上的任何位置来隐藏软键盘.有没有什么方法可以做到这一点?

Sam*_*ain 51

迄今为止最简单的解决方案

我找到了最简单的方法,现在您可以onTapOutside在 TextField 小部件中使用

 TextField(
       onTapOutside: (event) {
                  print('onTapOutside');
                    FocusManager.instance.primaryFocus?.unfocus();
                },)
Run Code Online (Sandbox Code Playgroud)

当文本字段获得焦点时,在 [TextFieldTapRegion] 组之外发生的每次点击都会调用此方法。

  • 这是最干净、最直接的方法,但在 GestureDetector 答案中几乎不可见。编辑应该把这个答案一直放在上面。 (9认同)
  • 有很多方法可以实现这一行为,但这个答案是最可靠的。 (2认同)

小智 38

您以错误的方式进行操作,只需尝试使用此简单方法来隐藏软键盘即可。您只需要用方法将整个屏幕包裹起来,GestureDetector然后用onTap方法编写此代码。

        FocusScope.of(context).requestFocus(new FocusNode());
Run Code Online (Sandbox Code Playgroud)

这是完整的示例:

new Scaffold(

body: new GestureDetector(
  onTap: () {

    FocusScope.of(context).requestFocus(new FocusNode());
  },
child: new Container(
   //rest of your code write here
    )
 )
Run Code Online (Sandbox Code Playgroud)

  • 实际上只有一个“行为:HitTestBehavior.translucent”,参数“onTap”总是被调用。如果没有这个参数,它对我来说无法在某些水龙头上工作。 (16认同)
  • 这个答案已经过时了。请在此处检查 v1.17.1 的更新答案(至少:))/sf/answers/4339088841/ (5认同)
  • onTapDown 比 onTap 更好。`onTapDown: (_) => FocusManager.instance.primaryFocus?.unfocus()` (2认同)

小智 16

总结整个屏幕GestureDetector作为

new Scaffold(

  body: new GestureDetector(
      onTap: () {
        // call this method here to hide soft keyboard
        FocusScope.of(context).requestFocus(new FocusNode());
      },
    child: new Container(
       -
       -
       -
        )
   )
Run Code Online (Sandbox Code Playgroud)


mah*_*mnj 15

从 Flutters 最新版本 v1.7.8+hotfix.2 开始,你可以使用 unfocus() 而不是 requestfocus() 来隐藏键盘

FocusScope.of(context).unfocus()
Run Code Online (Sandbox Code Playgroud)

所以每当你点击身体部位键盘时就会被隐藏

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        centerTitle: true,
        title: Text("Login"),
      ),
      body: GestureDetector(
        onTap: () {
          FocusScope.of(context).unfocus();
        },
        child: Container(...)
      ),
    );
  }

Run Code Online (Sandbox Code Playgroud)


pma*_*ias 14

*2022 年 9 月更新 :: 在 flutter 3.0.2 上

如果您有复杂的屏幕,我建议改用Listener。我之前遇到过问题:

使用“HitTestBehavior.opaque”捕获“GestureDetector”上的事件时存在滞后/延迟?

文档说:

考虑使用 GestureDetector 监听更高级别的手势,而不是监听原始指针事件

GestureDetector聆听高层的手势。我认为它造成了一些延迟或滞后。

我的解决方法:

Listener(
  behavior: HitTestBehavior.opaque,
  onPointerDown: (_) {
     FocusManager.instance.primaryFocus?.unfocus();
  },
  child: Scaffold()
Run Code Online (Sandbox Code Playgroud)

当您点击任意位置时,这将是捕获事件。


Geo*_*rge 12

更新

从2019年5月上旬开始,FocusNode现在有unfocus方法:

取消任何未解决的焦点请求。

无论此节点是否曾经请求过焦点,都可以安全地调用此方法。

使用unfocus,如果你宣布一个FocusNode以编程方式集中文本字段:

final focusNode = FocusNode();

// ...

focusNode.unfocus();
Run Code Online (Sandbox Code Playgroud)

我的原始答案建议detach方法-仅在需要FocusNode完全摆脱使用时才使用。如果您打算将其保留-请unfocus改用。

如果您尚未FocusNode明确声明,请使用“常规”方法:

FocusScope.of(context).requestFocus(new FocusNode());
Run Code Online (Sandbox Code Playgroud)

原始答案

我看到每个人都FocusScope.of(context).requestFocus(new FocusNode());习惯于使文本字段失去焦点,这对我来说似乎是错误的。

IMO仅会创建一个新的无用的对象,该对象会一直悬在用户使用'real'敲击文本字段之前FocusNode

如果您正在寻找一种“正确”的方法来1)消除键盘2)取消焦点文本字段-我可能已经找到了正确的方法:

FocusScope.of(context).detach();
Run Code Online (Sandbox Code Playgroud)

官方文档说,detach即使没有焦点,也可以安全使用。


但是,如果您只想隐藏键盘而不丢失文本字段焦点(出于某种原因),则可以尝试以下操作:

import 'package:flutter/services.dart' show SystemChannels;

SystemChannels.textInput.invokeMethod('TextInput.hide');
Run Code Online (Sandbox Code Playgroud)


omn*_*sia 12

正如一个小的旁注:

如果您使用ListView它的keyboardDismissBehavior属性可能会感兴趣:

ListView(
  keyboardDismissBehavior: ScrollViewKeyboardDismissBehavior.onDrag,
  children: [],
)
Run Code Online (Sandbox Code Playgroud)

  • 你的小旁注很大! (2认同)

Cha*_*cen 8

如果您希望在应用程序的任何屏幕上都可以访问该行为,请使用 GestureDetector 包装 MaterialApp:

// main.dart
import 'package:flutter/material.dart';

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

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return GestureDetector(
      onTap: () {
        FocusScopeNode currentFocus = FocusScope.of(context);

        if (!currentFocus.hasPrimaryFocus) {
          currentFocus.unfocus();
        }
      },
      child: MaterialApp(
        title: 'Flutter Demo',
        theme: ThemeData(
          primarySwatch: Colors.blue,
        ),
        home: MyHomePage(),
      ),
    );
  }
}
Run Code Online (Sandbox Code Playgroud)

检查 hasPrimaryFocus 是必要的,以防止 Flutter 在尝试使树顶部的节点不聚焦时抛出异常。

(最初由 Flutter Igniter 博客的 James Dixon 提供)

  • 调用了“unfocus”,但什么也没发生。目前的焦点并没有失去。 (2认同)

ate*_*kov 6

我已经添加了这一行

behavior: HitTestBehavior.opaque,
Run Code Online (Sandbox Code Playgroud)

到GestureDetector,它现在似乎可以按预期运行。

 @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text(AppLocalizations.of(context).calculatorAdvancedStageTitle),
      ),
      body: GestureDetector(
        behavior: HitTestBehavior.opaque,
        onTap: () {
          FocusScope.of(context).requestFocus(new FocusNode());
        },
        child: Padding(
          padding: const EdgeInsets.only(
            left: 14,
            top: 8,
            right: 14,
            bottom: 8,
          ),
          child: Text('Work'),
        ),
      )
    );
  }
Run Code Online (Sandbox Code Playgroud)


Vya*_*lav 6

GestureDetector(
  onTap: () {
        FocusScope.of(context).requestFocus(FocusNode());
  },
  behavior: HitTestBehavior.translucent,
  child: rootWidget
)
Run Code Online (Sandbox Code Playgroud)


Nix*_*gei 5

onPressed: () {
    FocusScope.of(context).unfocus();
},
Run Code Online (Sandbox Code Playgroud)

这对我有用。


Rud*_*wal 5

如果您想以“正确的方式”执行此操作,请使用 Listener 而不是 GestureDetector。

GestureDetector 仅适用于“单击”,这并不代表可以执行的所有可能的手势。

Listener(
  onPointerDown: (_) {
    FocusScopeNode currentFocus = FocusScope.of(context);
    if (!currentFocus.hasPrimaryFocus) {
      currentFocus.focusedChild.unfocus();
    }
  },
  child: MaterialApp(...),
);
Run Code Online (Sandbox Code Playgroud)


shu*_*ham 5

这将适用于最新的颤振版本。

GestureDetector(
  onTap: () {
    FocusScopeNode currentFocus = FocusScope.of(context);

    if (!currentFocus.hasPrimaryFocus &&
        currentFocus.focusedChild != null) {
      FocusManager.instance.primaryFocus.unfocus();
    }
  },
  child: MaterialApp(
    theme: ThemeData.dark().copyWith(
      primaryColor: Color(0xFF0A0E21),
      scaffoldBackgroundColor: Color(0xFF0A0E21),
    ),
    home: LoginUI(),
  ),
);
Run Code Online (Sandbox Code Playgroud)


Rit*_*mar 5

child: Form(
    child: Column(
        children: [
            TextFormField(
                decoration: InputDecoration(
                        labelText: 'User Name', hintText: 'User Name'),
                onTapOutside: (PointerDownEvent event) {
                    FocusScope.of(context).requestFocus(_unUsedFocusNode);
                },
            ),
        ],
    ),
),
Run Code Online (Sandbox Code Playgroud)

定义焦点节点

FocusNode _unUsedFocusNode = FocusNode();
Run Code Online (Sandbox Code Playgroud)

重写 TextFromField 中的 onTapOutside 方法

onTapOutside: (PointerDownEvent event) {
  FocusScope.of(context).requestFocus(_unUsedFocusNode);
},
Run Code Online (Sandbox Code Playgroud)

编辑:

Note: it will work in sdk Flutter 3.6.0-0.1.pre Dart SDK 2.19.0-374.1.beta
Run Code Online (Sandbox Code Playgroud)