简体   繁体   English

在 Flutter 中仅使一个小部件浮在键盘上方

[英]Make only one widget float above the keyboard in Flutter

I want to display a "Close keyboard" button above the keyboard when it is visible.我想在键盘可见时在键盘上方显示一个“关闭键盘”按钮。

I know that the resizeToAvoidBottomInset can impact how the keyboard interact with the rest of the application, however it doesn't do exactly what I want.我知道 resizeToAvoidBottomInset 会影响键盘与应用程序的 rest 交互的方式,但它并不能完全满足我的要求。

I have a background image and others widgets (not shown in the sample below) which should not be resized and not moved when the keyboards is shown.我有一个背景图像和其他小部件(未在下面的示例中显示),它们在显示键盘时不应调整大小和移动。 This is an ok behavior when the resizeToAvoidBottomInset attribute is set to false.resizeToAvoidBottomInset属性设置为 false 时,这是一个正常的行为。

However, I would like to add a button which should appear above the keyboard.但是,我想添加一个应该出现在键盘上方的按钮。

How can I do that?我怎样才能做到这一点? I only want one widget floating above the keyboard, not all the app.我只希望一个小部件漂浮在键盘上方,而不是所有应用程序。

Here is a sample code:这是一个示例代码:

import 'dart:async';

import 'package:flutter/material.dart';

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

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    var home = MyHomePage(title: 'Flutter Demo Home Page');
    return MaterialApp(
      title: 'Flutter Demo',
      theme: ThemeData(
        primarySwatch: Colors.blue,
      ),
      home: home,
    );
  }
}

class MyHomePage extends StatefulWidget {
  MyHomePage({Key key, this.title}) : super(key: key);
  final String title;

  @override
  _MyHomePageState createState() => _MyHomePageState();
}

class _MyHomePageState extends State<MyHomePage> {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      resizeToAvoidBottomInset: false,
      appBar: AppBar(
        title: Text(widget.title),
      ),
      body: _getBody(),
      floatingActionButton: FloatingActionButton(
        onPressed: () {},
        tooltip: 'Increment',
        child: Icon(Icons.add),
      ),
    );
  }

  Widget _getBody() {
    return Stack(children: <Widget>[
      Container(
        decoration: BoxDecoration(
            image: DecorationImage(
                image: AssetImage("assets/sample.jpg"), fit: BoxFit.fitWidth)),
        // color: Color.fromARGB(50, 200, 50, 20),
        child: Column(
          children: <Widget>[TextField()],
        ),
      ),
      Positioned(
        bottom: 0,
        left: 0,
        right: 0,
        child: Container(
          height: 50,
          child: Text("Aboveeeeee"),
          decoration: BoxDecoration(color: Colors.pink),
        ),
      ),
    ]);
  }
}

Your Positioned widget has a bottom of 0, replacing with an appropriate value should do the job.您的Positioned小部件的bottom为 0,用适当的值替换应该可以完成这项工作。

MediaQuery.of(context).viewInsets.bottom will give you the value of the height covered by the system UI(in this case the keyboard). MediaQuery.of(context).viewInsets.bottom将为您提供系统 UI(在本例中为键盘)覆盖的高度值。

import 'dart:async';

import 'package:flutter/material.dart';

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

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    var home = MyHomePage(title: 'Flutter Demo Home Page');
    return MaterialApp(
      title: 'Flutter Demo',
      theme: ThemeData(
        primarySwatch: Colors.blue,
      ),
      home: home,
    );
  }
}

class MyHomePage extends StatefulWidget {
  MyHomePage({Key key, this.title}) : super(key: key);
  final String title;

  @override
  _MyHomePageState createState() => _MyHomePageState();
}

class _MyHomePageState extends State<MyHomePage> {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      resizeToAvoidBottomInset: false,
      appBar: AppBar(
        title: Text(widget.title),
      ),
      body: _getBody(),
      floatingActionButton: FloatingActionButton(
        onPressed: () {},
        tooltip: 'Increment',
        child: Icon(Icons.add),
      ),
    );
  }

  Widget _getBody() {
    return Stack(children: <Widget>[
      Container(
        decoration: BoxDecoration(
            image: DecorationImage(
                image: AssetImage("assets/sample.jpg"), fit: BoxFit.fitWidth)),
        // color: Color.fromARGB(50, 200, 50, 20),
        child: Column(
          children: <Widget>[TextField()],
        ),
      ),
      Positioned(
        bottom: MediaQuery.of(context).viewInsets.bottom,
        left: 0,
        right: 0,
        child: Container(
          height: 50,
          child: Text("Aboveeeeee"),
          decoration: BoxDecoration(color: Colors.pink),
        ),
      ),
    ]);
  }
}

gif

To achieve keyboard-visibility-based animated padding, here are a few modifications over @10101010's great answer:为了实现基于键盘可见性的动画填充,这里是对@10101010 的好答案的一些修改:

If you want the bottom change when keyboard changes visibility to be animated AND you want extra padding under your floating child then:如果您希望在键盘更改可见性时bottom更改为动画,并且您希望在浮动子项下有额外的填充,那么:

1- Use keyboard_visibility flutter pub 1- 使用keyboard_visibility flutter pub

To listen when keyboard is appearing/disappearing, like so:要在键盘出现/消失时收听,如下所示:

  bool isKeyboardVisible = false;

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

    KeyboardVisibilityNotification().addNewListener(
      onChange: (bool visible) {
        isKeyboardVisible = visible;
      },
    );
  }

Optionally you can write your own native plugins, but it's already there you can check the pub's git repo.您可以选择编写自己的本机插件,但它已经存在,您可以检查 pub 的 git repo。

2- Consume visibility flag in your AnimatedPostioned : 2- 在AnimatedPostioned可见性标志:

For fine-tuned animated padding, like so:对于微调的动画填充,如下所示:

Widget _getBody() {
    double bottomPadding = 0;
    if (isKeyboardVisible) {
      // when keyboard is shown, our floating widget is above the keyboard and its accessories by `16`
      bottomPadding = MediaQuery.of(context).viewInsets.bottom + 16;
    } else {
      // when keyboard is hidden, we should have default spacing
      bottomPadding = 48; // MediaQuery.of(context).size.height * 0.15;
    }

    return Stack(children: <Widget>[
      Container(
        decoration: BoxDecoration(
            image: DecorationImage(
                image: AssetImage("assets/sample.jpg"), fit: BoxFit.fitWidth)),
        // color: Color.fromARGB(50, 200, 50, 20),
        child: Column(
          children: <Widget>[TextField()],
        ),
      ),
      AnimatedPositioned(
        duration: Duration(milliseconds: 500),
        bottom: bottomPadding,
        left: 0,
        right: 0,
        child: Container(
          height: 50,
          child: Text("Aboveeeeee"),
          decoration: BoxDecoration(color: Colors.pink),
        ),
      ),
    ]);
}

3- Keyboard-specific animation curve and duration for synchronized animation 3- 键盘特定的动画曲线和同步动画的持续时间

For now this is still an known ongoing issue目前这仍然是一个已知的持续问题

检查这个包,它可以在键盘上方显示一个关闭按钮。

You can use bottomSheet parameter of the Scaffold, which keep a persistent bottom sheet.您可以使用 Scaffold 的 bottomSheet 参数,它可以保持一个持久的底部表。 See below code.见下面的代码。

class InputScreen extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: const Text('Close')),
      bottomSheet: Container(
          padding: const EdgeInsets.symmetric(horizontal: 18, vertical: 16),
          color: Colors.black,
          child: const SizedBox(width: double.infinity, height: 10)),
      body: Column(
        children: [
          const TextField(
            decoration: InputDecoration(
              border: OutlineInputBorder(),
              hintText: 'Enter your input here',
            ),
          ),
          ElevatedButton(
            onPressed: () {},
            child: const Text('Submit'),
          ),
        ],
      ),
    );
  }
}

You can use the bottomSheet of a Scaffold widget.您可以使用Scaffold小部件的bottomSheet

Example:例子:

    return Scaffold(
      appBar: AppBar(
        title: const Text("New Game"),
      ),
      bottomSheet: Container(
          padding: const EdgeInsets.symmetric(horizontal: 18, vertical: 16),
          color: Colors.blue,
          child: const SizedBox(
            width: double.infinity,
            height: 20,
            child: Text("Above Keyboard"),
          ))
...
)

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM