【问题标题】:Make only one widget float above the keyboard in Flutter在 Flutter 中只让一个小部件漂浮在键盘上方
【发布时间】:2019-11-17 17:50:59
【问题描述】:

我想在键盘可见时在键盘上方显示一个“关闭键盘”按钮。

我知道 resizeToAvoidBottomInset 会影响键盘与应用程序其余部分的交互方式,但它并不能完全满足我的要求。

我有一个背景图像和其他小部件(未在下面的示例中显示),它们在显示键盘时不应调整大小和移动。当 resizeToAvoidBottomInset 属性设置为 false 时,这是一个正常的行为。

不过,我想添加一个应该出现在键盘上方的按钮。

我该怎么做?我只希望一个小部件悬浮在键盘上方,而不是所有应用程序。

这是一个示例代码:

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

【问题讨论】:

    标签: flutter keyboard widget floating


    【解决方案1】:

    您的 Positioned 小部件的 bottom 为 0,替换为适当的值即可。

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

    【讨论】:

    • 这是如何工作的?每次键盘出现后它都会自然重建吗?
    【解决方案2】:

    2022 年更新

    合并了一个 PR,它提供了用于关闭/打开键盘的平台同步动画。请参阅PR in effect here

    详细解答

    为了实现基于键盘可见性的动画填充,以下是对 @10101010 的最佳答案的一些修改:

    如果您希望在键盘更改可见性时更改bottom 以进行动画处理并且您希望在浮动子项下有额外的填充,那么:

    1- 使用keyboard_visibilityflutter pub

    在键盘出现/消失时收听,如下所示:

      bool isKeyboardVisible = false;
      
      @override
      void initState() {
        super.initState();
    
        KeyboardVisibilityNotification().addNewListener(
          onChange: (bool visible) {
            isKeyboardVisible = visible;
          },
        );
      }
    

    您可以选择编写自己的本机插件,但它已经存在,您可以检查 pub 的 git repo。

    2- 在您的AnimatedPostioned 中使用可见性标志:

    对于微调的动画填充,如下所示:

    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- 特定于键盘的动画曲线和同步动画的持续时间

    目前这仍然是known ongoing issue

    【讨论】:

      【解决方案3】:

      您可以使用 Scaffold 的 bottomSheet 参数,它保持一个持久的底部工作表。请参阅下面的代码。

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

      【讨论】:

        【解决方案4】:

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

        【讨论】:

        • 该软件包很有趣,并且与我想做的事情相同,但是在我的情况下,@10101010 提到的解决方案更容易实现。
        猜你喜欢
        • 2019-01-10
        • 1970-01-01
        • 2012-03-20
        • 2020-11-07
        • 2022-12-17
        • 2021-09-16
        • 2019-01-30
        • 2021-08-01
        • 1970-01-01
        相关资源
        最近更新 更多