ฉันจะปิดแป้นพิมพ์บนหน้าจอได้อย่างไร


140

ฉันกำลังรวบรวมข้อมูลของผู้ใช้ด้วย a TextFormFieldและเมื่อผู้ใช้กดที่FloatingActionButtonระบุว่าเสร็จแล้วฉันต้องการปิดแป้นพิมพ์บนหน้าจอ

ฉันจะทำให้คีย์บอร์ดหายไปโดยอัตโนมัติได้อย่างไร

import 'package:flutter/material.dart';

class MyHomePage extends StatefulWidget {
  MyHomePageState createState() => new MyHomePageState();
}

class MyHomePageState extends State<MyHomePage> {
  TextEditingController _controller = new TextEditingController();

  @override
  Widget build(BuildContext context) {
    return new Scaffold(
      appBar: new AppBar(),
      floatingActionButton: new FloatingActionButton(
        child: new Icon(Icons.send),
        onPressed: () {
          setState(() {
            // send message
            // dismiss on screen keyboard here
            _controller.clear();
          });
        },
      ),
      body: new Container(
        alignment: FractionalOffset.center,
        padding: new EdgeInsets.all(20.0),
        child: new TextFormField(
          controller: _controller,
          decoration: new InputDecoration(labelText: 'Example Text'),
        ),
      ),
    );
  }
}

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

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

Collin คำตอบที่สองจาก @Pascal ควรเป็นคำตอบที่ได้รับการปรับปรุงและแก้ไขแล้ว
แจ็ค

คำตอบ:


235

ในขณะที่ Flutter v1.7.8 + hotfix.2 วิธีที่จะไปคือ:

FocusScope.of(context).unfocus()

แสดงความคิดเห็นเกี่ยวกับการประชาสัมพันธ์ว่า:

ตอนนี้ # 31909 (be75fb3) มาถึงแล้วคุณควรใช้ FocusScope.of(context).unfocus()แทน FocusScope.of(context).requestFocus(FocusNode())เนื่องจากFocusNodeมี ChangeNotifiersและควรกำจัดอย่างเหมาะสม

-> ห้ามใช̶้r̶e̶q̶u̶e̶s̶t̶F̶o̶c̶u̶s̶(̶F̶o̶c̶u̶s̶N̶o̶d̶e̶(̶)̶อีกต่อไป

 F̶o̶c̶u̶s̶S̶c̶o̶p̶e̶.̶o̶f̶(̶c̶o̶n̶t̶e̶x̶t̶)̶.̶r̶e̶q̶u̶e̶s̶t̶F̶o̶c̶u̶s̶(̶F̶o̶c̶u̶s̶N̶o̶d̶e̶(̶)̶)̶;̶

1
ทำงานให้ฉันในโปรแกรมแก้ไขด่วน v1.7.8 + hotfix.4
Rajesh Jr.

2
ได้ผลสำหรับฉันคำตอบนี้ควรถูกปิดบังว่าเป็นคำตอบที่ถูกต้อง
user3087360

@kine ช่วยอธิบายให้ละเอียดหน่อยได้ไหม? ตามเอกสารนี้เป็นวิธีการทำ (ดูapi.flutter.dev/flutter/widgets/FocusNode/unfocus.html )
Pascal

@Pascal ใช่ฉันได้อ่านเอกสารแล้วและนี่น่าจะเป็นทางออกที่ฉันต้องการ แต่ในแอปของฉันมันใช้ไม่ได้เสมอไป (เป็นรูปแบบที่ค่อนข้างซับซ้อนที่มีหลายTextFields และวิดเจ็ตแก้ไขอื่น ๆ ) ไม่รู้ทำไม แต่บางครั้งก็unfocusไม่มีผลใด ๆ การแทนที่ด้วยโซลูชันที่ยอมรับ (ไม่มีการเปลี่ยนแปลงอื่น ๆ ) ช่วยแก้ปัญหาได้ อาจจะเกี่ยวข้องกับตำแหน่งที่unfocusเรียกจาก ฉันต้องเรียกมันว่าจากCheckBoxListTile.onChangedเพื่อปิดแป้นพิมพ์เมื่อผู้ใช้โต้ตอบกับวิดเจ็ตช่องทำเครื่องหมายและจากตำแหน่งอื่นที่คล้ายคลึงกัน ฉันจำตำแหน่งของปัญหาไม่ได้
kine

@kine ขอบคุณสำหรับคำอธิบาย การยกตัวอย่างให้กับทีม Flutter จะน่าทึ่งมาก ;-)
Pascal

211

หมายเหตุ:คำตอบนี้ล้าสมัย ดูคำตอบสำหรับรุ่นใหม่ของกระพือ

คุณสามารถปิดแป้นพิมพ์ได้โดยละทิ้งโฟกัสของแป้นพิมพ์TextFormFieldและมอบให้กับสิ่งที่ไม่ได้ใช้FocusNode:

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

คุณจะติดตั้งโค้ดนี้ที่ไหน ใน TextFormField; อาจจะหลังจากonChanged:หรือในการทำงานของปุ่มที่คุณกำหนดเอง?
Charles Jr

@CharlesJr ฉันทำมันในการกระทำของปุ่มของฉัน
Duncan Jones

คุณสามารถใช้แพ็คเกจของฉันได้ถ้าคุณต้องการ :) pub.dartlang.org/packages/keyboard_actions
diegoveloper

17
นี่คือก่อน Flutter v1.7.8 - ดูคำตอบstackoverflow.com/a/56946311/8696915ซึ่งให้FocusScope.of(context).unfocus()
Richard Johnson

1
อย่าทำเช่นนี้หากคุณสามารถเข้าถึง. unfocus () เพราะจะทำให้หน่วยความจำรั่วไหล FocusNode () ใหม่นั้นจะไม่ถูกล้าง ดูความคิดเห็นเกี่ยวกับ. unfocus ()
Michael Peterson

70

วิธีแก้ไขด้วย FocusScope ไม่ได้ผลสำหรับฉัน ฉันพบอีก:

import 'package:flutter/services.dart';

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

มันช่วยแก้ปัญหาของฉันได้


การเรียกสิ่งนี้ไม่ได้ซ่อนแป้นพิมพ์สำหรับฉัน ควรใช้งานได้ทั้งบน Android และ iOS หรือไม่
Jardo

ทำงานให้ฉันบน iOS (12.1, iPhone 5s) และ Android (Pixel 3)
Jannie Theunissen

คุณวางสิ่งนี้ไว้ที่ไหน? ฉันลองเพิ่มเป็นรหัสบิตแรกในแอปแล้วก็ไม่ได้ทำอะไรเลย
Justin808

คุณหมายถึงอะไร - "บิตแรกของโค้ด"? แทรกในbuildวิธีการตัวอย่างเช่น
Andrey Turkovsky

1
มีสิ่งนี้เทียบเท่ากับปุ่มกดตัวเลขหรือไม่
Daniel Maksimovich

20

สำหรับ Flutter 1.17.3 (ช่องสัญญาณเสถียร ณ เดือนมิถุนายน 2020) ให้ใช้

FocusManager.instance.primaryFocus.unfocus();

13

ตัวอย่างการนำไปใช้. unfocus () เพื่อซ่อนแป้นพิมพ์อัตโนมัติเมื่อเลื่อนรายการ

FocusScope.of(context).unfocus();

คุณสามารถค้นหาได้ที่

https://github.com/flutter/flutter/issues/36869#issuecomment-518118441

ขอบคุณข้อมูล szotp


1
ใช่นี่เป็นวิธีที่ง่ายที่สุดที่จะทำ
มิทันนาถ

12

ไม่มีวิธีแก้ปัญหาข้างต้นไม่ได้ผลสำหรับฉัน

Flutter แนะนำสิ่งนี้ - วางวิดเจ็ตของคุณไว้ในGestureDetector () ใหม่ซึ่งการแตะจะซ่อนแป้นพิมพ์และ onTap ใช้FocusScope.of (บริบท) .requestFocus (FocusNode ใหม่ ())

class Home extends StatelessWidget {
@override
  Widget build(BuildContext context) {
    var widget = new MaterialApp(
        home: new Scaffold(
            body: new Container(
                height:500.0,
                child: new GestureDetector(
                    onTap: () {
                        FocusScope.of(context).requestFocus(new FocusNode());
                    },
                    child: new Container(
                        color: Colors.white,
                        child:  new Column(
                            mainAxisAlignment:  MainAxisAlignment.center,
                            crossAxisAlignment: CrossAxisAlignment.center,

                            children: [
                                new TextField( ),
                                new Text("Test"),                                
                            ],
                        )
                    )
                )
            )
        ),
    );

    return widget;
}}

12

รหัสต่อไปนี้ช่วยฉันซ่อนแป้นพิมพ์

   void initState() {
   SystemChannels.textInput.invokeMethod('TextInput.hide');
   super.initState();
   }

8
GestureDetector(
          onTap: () {
            FocusScope.of(context).unfocus();
          },
          child:Container(
    alignment: FractionalOffset.center,
    padding: new EdgeInsets.all(20.0),
    child: new TextFormField(
      controller: _controller,
      decoration: new InputDecoration(labelText: 'Example Text'),
    ),
  ), })

ลองใช้ท่าทางสัมผัส


ขอบคุณ ... เอาวิธีแก้ปัญหานี้
Ajay Kumar

6

เช่นเดียวกับใน Flutter ทุกอย่างเป็นวิดเจ็ตฉันตัดสินใจที่จะSystemChannels.textInput.invokeMethod('TextInput.hide');รวมไฟล์FocusScope.of(context).requestFocus(FocusNode());แนวทางในโมดูลยูทิลิตี้สั้น ๆ พร้อมวิดเจ็ตและมิกซ์อิน

ด้วยวิดเจ็ตคุณสามารถรวมวิดเจ็ตใด ๆ (สะดวกมากเมื่อใช้การสนับสนุน IDE ที่ดี) ด้วยKeyboardHiderวิดเจ็ต:

class SimpleWidget extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return KeyboardHider(
      /* Here comes a widget tree that eventually opens the keyboard,
       * but the widget that opened the keyboard doesn't necessarily
       * takes care of hiding it, so we wrap everything in a
       * KeyboardHider widget */
      child: Container(),
    );
  }
}

ด้วยการมิกซ์อินคุณสามารถเรียกใช้การซ่อนแป้นพิมพ์จากสถานะหรือวิดเจ็ตใด ๆ เมื่อมีการโต้ตอบ:

class SimpleWidget extends StatefulWidget {
  @override
  _SimpleWidgetState createState() => _SimpleWidgetState();
}

class _SimpleWidgetState extends State<SimpleWidget> with KeyboardHiderMixin {
  @override
  Widget build(BuildContext context) {
    return RaisedButton(
      onPressed: () {
        // Hide the keyboard:
        hideKeyboard();
        // Do other stuff, for example:
        // Update the state, make an HTTP request, ...
      },
    );
  }
}

เพียงสร้างkeyboard_hider.dartไฟล์และวิดเจ็ตและมิกซ์อินก็พร้อมใช้งาน:

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

/// Mixin that enables hiding the keyboard easily upon any interaction or logic
/// from any class.
abstract class KeyboardHiderMixin {
  void hideKeyboard({
    BuildContext context,
    bool hideTextInput = true,
    bool requestFocusNode = true,
  }) {
    if (hideTextInput) {
      SystemChannels.textInput.invokeMethod('TextInput.hide');
    }
    if (context != null && requestFocusNode) {
      FocusScope.of(context).requestFocus(FocusNode());
    }
  }
}

/// A widget that can be used to hide the text input that are opened by text
/// fields automatically on tap.
///
/// Delegates to [KeyboardHiderMixin] for hiding the keyboard on tap.
class KeyboardHider extends StatelessWidget with KeyboardHiderMixin {
  final Widget child;

  /// Decide whether to use
  /// `SystemChannels.textInput.invokeMethod('TextInput.hide');`
  /// to hide the keyboard
  final bool hideTextInput;
  final bool requestFocusNode;

  /// One of hideTextInput or requestFocusNode must be true, otherwise using the
  /// widget is pointless as it will not even try to hide the keyboard.
  const KeyboardHider({
    Key key,
    @required this.child,
    this.hideTextInput = true,
    this.requestFocusNode = true,
  })  : assert(child != null),
        assert(hideTextInput || requestFocusNode),
        super(key: key);

  @override
  Widget build(BuildContext context) {
    return GestureDetector(
      behavior: HitTestBehavior.opaque,
      onTap: () {
        hideKeyboard(
          context: context,
          hideTextInput: hideTextInput,
          requestFocusNode: requestFocusNode,
        );
      },
      child: child,
    );
  }
}

4

คุณสามารถใช้unfocus()วิธีการจากFocusNodeชั้นเรียน

import 'package:flutter/material.dart';

class MyHomePage extends StatefulWidget {
  MyHomePageState createState() => new MyHomePageState();
}

class MyHomePageState extends State<MyHomePage> {
  TextEditingController _controller = new TextEditingController();
  FocusNode _focusNode = new FocusNode(); //1 - declare and initialize variable

  @override
  Widget build(BuildContext context) {
    return new Scaffold(
      appBar: new AppBar(),
      floatingActionButton: new FloatingActionButton(
        child: new Icon(Icons.send),
        onPressed: () {
            _focusNode.unfocus(); //3 - call this method here
        },
      ),
      body: new Container(
        alignment: FractionalOffset.center,
        padding: new EdgeInsets.all(20.0),
        child: new TextFormField(
          controller: _controller,
          focusNode: _focusNode, //2 - assign it to your TextFormField
          decoration: new InputDecoration(labelText: 'Example Text'),
        ),
      ),
    );
  }
}

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

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

1
Hi! จะเป็นการดีที่สุดหากคุณสามารถแก้ไขคำตอบเพื่อเพิ่มบริบทเพิ่มเติมให้กับคำตอบของคุณ
grooveplex

1
ทางออกที่ดีที่สุดโดยมีการเข้ารหัสน้อยที่สุด
Val

ใช่มันจะลบโฟกัสหากแตะที่วิดเจ็ตเฉพาะ ไม่สามารถเพิ่มลงในทุกวิดเจ็ตในแอปของฉัน
Dpedrinha

การแตะที่วิดเจ็ตเป็นเพียงวิธีการโทรunfocusวิธีหนึ่ง หากคุณไม่ต้องการส่งสแปมสิ่งนี้ในแอปของคุณคุณสามารถใช้วิธีอื่นเช่นTextFormFieldเหตุการณ์การเปลี่ยนแปลงหรือรูปแบบปฏิกิริยาขึ้นอยู่กับสถาปัตยกรรมของแอปของคุณ
Evandro Ap. ส

4

ดูเหมือนแนวทางที่แตกต่างกันสำหรับเวอร์ชันต่างๆ ฉันใช้ Flutter v1.17.1 และด้านล่างใช้ได้ผลสำหรับฉัน

onTap: () {
    FocusScopeNode currentFocus = FocusScope.of(context);
    if (!currentFocus.hasPrimaryFocus && currentFocus.focusedChild != null) {
       currentFocus.focusedChild.unfocus();
    }
}

1
_dismissKeyboard(BuildContext context) {
   FocusScope.of(context).requestFocus(new FocusNode());
}

@override
Widget build(BuildContext context) {

return new GestureDetector(
    onTap: () {
    this._dismissKeyboard(context);
    },
    child: new Container(
    color: Colors.white,
    child: new Column(
        children: <Widget>[/*...*/],
    ),
    ),
 );
}

0

ลองใช้ตัวควบคุมการแก้ไขข้อความ ที่จุดเริ่มต้น,

    final myController = TextEditingController();
     @override
  void dispose() {
    // Clean up the controller when the widget is disposed.
    myController.dispose();
    super.dispose();
  }

และในงานแถลงข่าว

onPressed: () {
            commentController.clear();}

สิ่งนี้จะปิดคีย์บอร์


0

สรุปได้ว่านี่คือโซลูชันที่ใช้งานได้สำหรับ Flutter 1.17:

ห่อวิดเจ็ตของคุณดังนี้:

GestureDetector(
        onTap: FocusScope.of(context).unfocus,
        child: YourWidget(),
);
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.