Làm cách nào để loại bỏ bàn phím ảo?


139

Tôi đang thu thập thông tin nhập của người dùng bằng a TextFormFieldvà khi người dùng nhấn vào FloatingActionButtondấu cho biết họ đã hoàn tất, tôi muốn loại bỏ bàn phím ảo.

Làm cách nào để làm cho bàn phím tự động biến mất?

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, Câu trả lời thứ hai từ @Pascal phải là câu trả lời được cập nhật, sửa chữa.
Jack

Câu trả lời:


226

Kể từ Flutter v1.7.8 + hotfix.2, cách để thực hiện là:

FocusScope.of(context).unfocus()

Bình luận về PR về điều đó:

Bây giờ, # 31909 (be75fb3) đã hạ cánh, bạn nên sử dụng FocusScope.of(context).unfocus()thay vì FocusScope.of(context).requestFocus(FocusNode()), vì FocusNodes ChangeNotifiersvà nên được xử lý đúng cách.

-> KHÔNG sử dụng ̶r̶e̶q̶u̶e̶s̶t̶F̶o̶c̶u̶s̶(̶F̶o̶c̶u̶s̶N̶o̶d̶e̶(̶)̶nữa.

 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
Đã làm việc cho tôi trên hotfix v1.7.8 + hotfix.4
Rajesh Jr.

2
công việc đối với tôi, câu trả lời này nên được đeo mặt nạ như đúng một
user3087360

@kine bạn có thể vui lòng nói rõ hơn không? Đây là cách thực hiện (xem api.flutter.dev/flutter/widgets/FocusNode/unfocus.html )
Pascal

@Pascal Có Tôi đã đọc tài liệu và đây sẽ là giải pháp ưa thích của tôi, nhưng trong ứng dụng của tôi, nó không hoạt động luôn (một dạng khá phức tạp với một số TextFields và các tiện ích chỉnh sửa khác). Tôi không biết tại sao nhưng đôi khi unfocuskhông có bất kỳ tác dụng. Thay thế nó bằng giải pháp được chấp nhận (không có thay đổi nào khác) sẽ khắc phục được sự cố. Có thể nó liên quan đến vị trí unfocusđược gọi từ đâu. Tôi cần phải gọi nó là từ CheckBoxListTile.onChangedloại bỏ bàn phím khi người dùng tương tác với tiện ích hộp kiểm và từ các vị trí tương tự khác. Tôi không nhớ chính xác vị trí vấn đề.
kine

@kine Cảm ơn vì lời giải thích. Cung cấp một ví dụ cho nhóm Flutter sẽ rất tuyệt vời ;-)
Pascal

207

Lưu ý: Câu trả lời này đã lỗi thời. Xem câu trả lời cho các phiên bản mới hơn của Flutter .

Bạn có thể loại bỏ bàn phím bằng cách lấy đi tiêu điểm của bàn phím TextFormFieldvà đưa nó cho một bàn phím không sử dụng FocusNode:

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

Bạn sẽ triển khai mã này ở đâu? Trong TextFormField; có thể sau onChanged:hoặc trong hành động của nút tùy chỉnh của bạn?
Charles Jr,

@CharlesJr Tôi làm điều đó trong hành động của nút của tôi.
Duncan Jones

bạn có thể sử dụng gói của tôi nếu bạn muốn :) pub.dartlang.org/packages/keyboard_actions
diegoveloper

17
Đây là trước Flutter v1.7.8 - xem câu trả lời stackoverflow.com/a/56946311/8696915 cung cấpFocusScope.of(context).unfocus()
Richard Johnson

1
Đừng làm điều này nếu bạn có quyền truy cập .unfocus () vì nó sẽ gây rò rỉ bộ nhớ. FocusNode () mới đó sẽ không bao giờ được làm sạch. Xem bình luận về .unfocus ()
Michael Peterson

70

Giải pháp với FocusScope không phù hợp với tôi. Tôi đã tìm thấy một cái khác:

import 'package:flutter/services.dart';

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

Nó đã giải quyết vấn đề của tôi.


Gọi này không ẩn bàn phím cho tôi. Nó có hoạt động trên cả Android và iOS không?
Jardo

Làm việc cho tôi trên iOS (12.1, iPhone 5s) và Android (Pixel 3)
Jannie Theunissen

Bạn đặt cái này ở đâu? Tôi đã thử chỉ thêm nó làm bit mã đầu tiên trong ứng dụng và nó không làm được gì cả.
Justin808,

Ý bạn là gì - "đoạn mã đầu tiên"? Chèn nó vào buildphương thức chẳng hạn.
Andrey Turkovsky,

1
có một tương đương cho điều này cho ký tự phím số không?
Daniel Maksimovich

19

Đối với Flutter 1.17.3 (kênh ổn định kể từ tháng 6 năm 2020), hãy sử dụng

FocusManager.instance.primaryFocus.unfocus();

12

Không có giải pháp nào ở trên không hiệu quả với tôi.

Flutter gợi ý điều này - Đặt tiện ích của bạn vào bên trong GestureDetector () mới, trên đó chạm sẽ ẩn bàn phím và onTap sử dụng FocusScope.of (context) .requestFocus (new 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

Mã sau đã giúp tôi ẩn bàn phím

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

thử cử chỉ này khi chạm


Cảm ơn ... đã giải pháp này
Ajay Kumar,

6

Vì trong Flutter, mọi thứ đều là một tiện ích, tôi quyết định kết SystemChannels.textInput.invokeMethod('TextInput.hide');hợpFocusScope.of(context).requestFocus(FocusNode()); cách tiếp cận trong một mô-đun tiện ích ngắn với một widget và một mixin trong đó.

Với tiện ích này, bạn có thể bọc bất kỳ tiện ích nào (rất thuận tiện khi sử dụng hỗ trợ IDE tốt) với KeyboardHidertiện ích:

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

Với mixin, bạn có thể kích hoạt ẩn bàn phím khỏi bất kỳ trạng thái hoặc tiện ích nào sau bất kỳ tương tác nào:

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

Chỉ cần tạo một keyboard_hider.darttệp và tiện ích con và mixin đã sẵn sàng để sử dụng:

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

Bạn có thể sử dụng unfocus()phương thức từ FocusNodelớp.

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
Chào! Sẽ là tốt nhất nếu bạn có thể chỉnh sửa câu trả lời của mình để thêm một chút ngữ cảnh vào câu trả lời của mình.
groplex vào

1
Giải pháp tốt nhất với số lượng mã hóa ít nhất
Val

Có, nó sẽ xóa tiêu điểm nếu chạm vào một tiện ích cụ thể. Không thể thêm nó vào mọi tiện ích con trên ứng dụng của tôi.
Dpedrinha

Nhấn vào một widget chỉ là một cách để gọi unfocusphương thức. Nếu bạn không muốn spam nội dung này trên ứng dụng của mình, bạn có thể sử dụng một cách khác, chẳng hạn như TextFormFieldsự kiện thay đổi hoặc mẫu phản ứng, tùy thuộc vào kiến ​​trúc ứng dụng của bạn.
Evandro Ap. S.

4

Có vẻ như các cách tiếp cận khác nhau cho phiên bản khác nhau. Tôi đang sử dụng Flutter v1.17.1 và phần bên dưới phù hợp với tôi.

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

thử sử dụng bộ điều khiển chỉnh sửa văn bản. lúc đầu,

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

và trong sự kiện báo chí trực tuyến,

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

điều này sẽ loại bỏ keybord.

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.