在屏幕上单击外部 TextField/anywhere 后,如何在颤动中隐藏软输入键盘?

How to hide soft input keyboard on flutter after clicking outside TextField/anywhere on screen?

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

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

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

GestureDetector 中将整个屏幕包裹为

new Scaffold(

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

你用错了方法,试试这个隐藏软键盘的简单方法。您只需要将整个屏幕包裹在 GestureDetector 方法和 onTap 方法中,并编写此代码。

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

完整示例如下:

new Scaffold(

body: new GestureDetector(
  onTap: () {
   
    FocusScope.of(context).requestFocus(new FocusNode());
  },
child: new Container(
   //rest of your code write here
    )
 )

更新(2021 年 5 月)

return GestureDetector(
      onTap: () => FocusManager.instance.primaryFocus?.unfocus(),
      child: Scaffold(
        appBar: AppBar(
          title: Text('Login'),
        ),
        body: Body(),
      ),
    );

即使您触摸 AppBar,这也会起作用,newoptional in Dart 2FocusManager.instance.primaryFocus 将 return 当前在小部件树中具有主要焦点的节点。

Conditional access in Dart with null-safety

我添加了这一行

behavior: HitTestBehavior.opaque,

到 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'),
        ),
      )
    );
  }

已更新

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

Cancels any outstanding requests for focus.

This method is safe to call regardless of whether this node has ever requested focus.

如果您为文本字段声明了 FocusNode,请使用 unfocus

final focusNode = FocusNode();

// ...

focusNode.unfocus();

我最初的回答建议使用 detach 方法 - 仅当您需要完全摆脱 FocusNode 时才使用它。如果您打算保留它 - 请改用 unfocus

如果您没有明确声明 FocusNode - 使用 unfocus 作为您当前上下文的 FocusScope

FocusScope.of(context).unfocus();

查看原始答案的修订历史。

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

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

FocusScope.of(context).unfocus()

因此,只要您点击 body 部分,键盘就会隐藏

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

onPressed: () {
    FocusScope.of(context).unfocus();
},

这对我有用。

maheshmnj 说的是真的,从 v1.7.8+hotfix.2 版本开始,您可以使用 unfocus() 而不是 requestfocus() 来隐藏键盘。

FocusScope.of(context).unfocus()

但就我而言,我仍然遇到很多布局错误,因为我导航到的屏幕无法处理布局。

════════ Exception Caught By rendering library ═════════════════════════════════
The following JsonUnsupportedObjectError was thrown during paint():
Converting object to an encodable object failed: Infinity
When the exception was thrown, this was the stack
#0      _JsonStringifier.writeObject  (dart:convert/json.dart:647:7)
#1      _JsonStringifier.writeMap  (dart:convert/json.dart:728:7)
#2      _JsonStringifier.writeJsonValue  (dart:convert/json.dart:683:21)
#3      _JsonStringifier.writeObject  (dart:convert/json.dart:638:9)
#4      _JsonStringifier.writeList  (dart:convert/json.dart:698:9)

这是通过在接收屏幕中插入“resizeToAvoidBottomInset: false”处理的 Scaffold()

@override
  Widget build(BuildContext context) {
    return Scaffold(
      resizeToAvoidBottomInset: false,   // HERE
      appBar: AppBar(
        centerTitle: true,
        title: Text("Receiving Screen "),
      ),
      body: Container(...)
      ),
    );
  }

如果您希望在应用的任何屏幕上都可以访问该行为,请使用 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(),
      ),
    );
  }
}

检查 hasPrimaryFocus 是必要的,以防止 Flutter 在尝试取消对树顶部节点的关注时抛出异常。

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

我刚刚开发了一个小程序包,可以为任何小部件提供您正在寻找的行为类型:keyboard_dismisser on pub.dev。你可以用它包裹整个页面,这样当点击任何不活动的小部件时键盘就会消失。

FocusScopeNode currentFocus = FocusScope.of(context);

    if (!currentFocus.hasPrimaryFocus) {
      currentFocus.unfocus();
    }

你应该在这里查看https://flutterigniter.com/dismiss-keyboard-form-lose-focus/

作为一个小旁注:

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

ListView(
  keyboardDismissBehavior: ScrollViewKeyboardDismissBehavior.onDrag,
  children: [],
)

如果你在堆栈上,试试这个

body: GestureDetector(
              onTap: () {
                FocusScope.of(context).requestFocus(new FocusNode());
              },
              child: Container(
                height: double.infinity,
                width: double.infinity,
                color: Colors.transparent,
                child: Stack(children: [
                  _CustomBody(_),
                  Positioned(
                      bottom: 15, right: 20, left: 20, child: _BotonNewList()),
                ]),
              ),
            ),

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

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

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

这将适用于最新的 flutter 版本。

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(),
  ),
);

这是最好的

Scaffold(
body: GestureDetector(
  onTap: () {
   if (messageFocusNode.hasFocus) {
     messageFocusNode.unfocus();
 }
},
child: new Container(
   //rest of your code write here
    )
 )

最适合我。

我从 Material App 开始换行,因为全球外部接触

FocusScopeNode currentFocus = FocusScope.of(context);
if (!currentFocus.hasPrimaryFocus && currentFocus.focusedChild != null) {
  FocusManager.instance.primaryFocus.unfocus();
}

下面解决,

我检查平台 iOS 只是因为 Android 可以关闭键盘 后退按钮

Listener(
  onPointerUp: (_) {
    if (Platform.isIOS) {
      FocusScopeNode currentFocus = FocusScope.of(context);
      if (!currentFocus.hasPrimaryFocus &&
          currentFocus.focusedChild != null) {
        FocusManager.instance.primaryFocus.unfocus();
      }
    }
  },
  child: MaterialApp(
    debugShowCheckedModeBanner: true,
    home: MyHomePage(),
    ...
  ),
),

很高兴你的编码。

Flutter 版本

这会起作用

 Widget build(BuildContext context) {
final textTheme = Theme.of(context).textTheme;
return GestureDetector(
  onTap: () {
    FocusScopeNode focus = FocusScope.of(context);
    if (!focus.hasPrimaryFocus && focus.focusedChild != null) {
      focus.focusedChild.unfocus();
    }
  },
  child: MaterialApp(
    title: 'Flutter Demo',

如果焦点在 webview 内,键盘从另一个屏幕或任何其他屏幕打开,然后使用以下方式隐藏键盘

import 'package:flutter/services.dart';

SystemChannels.textInput.invokeMethod('TextInput.hide');

这比添加 FocusScope.of(context).unfocus() 的解决方案更有效,因为该解决方案使我进入显示和隐藏键盘的循环

当用户点击屏幕的任何区域时,您需要隐藏键盘时,此处适合初学者的简单解决方案对您来说是最流畅的解决方案。希望对你有很大帮助。

步骤 - 1:您需要在全局 class,

中创建此方法

此方法将您的主要小部件包装到 GestureDetector 中,因此当用户在文本字段外点击时,它会自动隐藏键盘

Widget hideKeyboardWhileTapOnScreen(BuildContext context, {MaterialApp child}){

  return GestureDetector(
    onTap: () {
      if (Platform.isIOS) { //For iOS platform specific condition you can use as per requirement
        SystemChannels.textInput.invokeMethod('TextInput.hide');
        print("Keyboard Hide");
      }      
    },
    child: child,
  );
}

此方法将您的主要小部件包装到 Listener 中,因此当用户触摸并向上滚动时它会自动隐藏键盘

Widget hideKeyboardWhileTapOnScreen(BuildContext context, {MaterialApp child}){
  return Listener(
    onPointerUp: (_) {
      if (Platform.isIOS) {
        FocusScopeNode currentFocus = FocusScope.of(context);
        if (!currentFocus.hasPrimaryFocus &&
            currentFocus.focusedChild != null) {
          FocusManager.instance.primaryFocus.unfocus();
          print("Call keyboard listner  call");
        }
      }
    },
    child: child,
  );
}

步骤 - 2:这里是如何使用全局方法

@override
Widget build(BuildContext context) {
 
  return hideKeyboardWhileTapOnScreen(context,
    child: MaterialApp(
        debugShowCheckedModeBanner: false, home: Scaffold(body: setAppbar())),
  );
}

Widget setAppbar2() {
  return MaterialApp(
    debugShowCheckedModeBanner: false,
    theme: ThemeData(primarySwatch: Colors.orange),
    home: Scaffold(
      resizeToAvoidBottomInset: false,
      appBar: AppBar(),
    ),
  );
}

使用 Flutter 2.5 GestureDetector.OnTap 对我不起作用。

只有这个有效:

return GestureDetector(
      //keyboard pop-down
      onTapDown: (_) => FocusManager.instance.primaryFocus?.unfocus(),
      behavior: HitTestBehavior.translucent,
      child: Scaffold(

2021 年 11 月更新

根据新的 flutter webview documentation: 将这段代码放入给定的完整示例中将解决键盘关闭问题。

@override
   void initState() {
     super.initState();
         // Enable hybrid composition.
         if (Platform.isAndroid) WebView.platform = SurfaceAndroidWebView();
   }

完整示例代码:

 import 'dart:io';
 import 'package:webview_flutter/webview_flutter.dart';

 class WebViewExample extends StatefulWidget {
   @override
   WebViewExampleState createState() => WebViewExampleState();
 }

 class WebViewExampleState extends State<WebViewExample> {
   @override
   void initState() {
     super.initState();
         // Enable hybrid composition.
 if (Platform.isAndroid) WebView.platform = SurfaceAndroidWebView();
   }

   @override
   Widget build(BuildContext context) {
     return WebView(
       initialUrl: 'https://flutter.dev',
     );
   }
 }