如何为键盘外观上的Flutter布局制作动画

时间:2019-02-06 22:58:39

标签: ios dart flutter

我正在构建Flutter应用程序,主要用于iOS。

我的一个视图有一个文本字段,当您点击它时会出现iOS键盘。问题是-布局无法像在本地iOS应用中一样平滑地更改。取而代之的是,它甚至会在键盘打开动画完成之前立即跳到最终可用的屏幕高度。

我尝试将我的SafeArea元素包装在AnimatedSizeAnimatedContainer中-并没有帮助。

我的布局代码:

SafeArea(child:
  Column(children:[
    TextField(...)
  ])
)

当键盘出现时,如何使布局平滑调整大小?

预期:

how I expect it to be.gif

实际

how it is - laggy resizing in Flutter app.gif

6 个答案:

答案 0 :(得分:2)

此功能是必需的,但从2020年5月起尚未实现。请随时对其进行投票以使其具有更高的优先级:https://github.com/flutter/flutter/issues/19279

正在实施的同时,您可以使用https://pub.dev/packages/keyboard_attachable

答案 1 :(得分:1)

使用 AnimatedPadding Widget 可以实现所需的输出,虽然这并不完美,但总比没有好:d

Open issue as of 15/03/21, for reference

import 'dart:math';

import 'package:flutter/material.dart';

final Color darkBlue = Color.fromARGB(255, 18, 32, 47);

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

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      theme: ThemeData.dark().copyWith(scaffoldBackgroundColor: darkBlue),
      debugShowCheckedModeBanner: false,
      home: Scaffold(
        body: Center(
          child: MyWidget(),
        ),
      ),
    );
  }
}

class MyWidget extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return SafeArea(
      bottom: false,
      child: Scaffold(
          // !!! Important part > to disable default scaffold insets
          resizeToAvoidBottomInset: false,
          appBar: AppBar(
            title: Text("Appbar Title"),
          ),
          body: Stack(
            children: [
              Scrollbar(
                child: ListView.builder(
                  padding: EdgeInsets.all(0.0),
                  itemCount: 30,
                  itemBuilder: (context, i) {
                    return Container(
                      height: 100,
                      width: double.infinity,
                      color: Colors
                          .primaries[Random().nextInt(Colors.primaries.length)],
                    );
                  },
                ),
              ),
              Align(
                alignment: Alignment.bottomLeft,
                child: AnimatedPadding(
                    padding: MediaQuery.of(context).viewInsets,
                    // You can change the duration and curve as per your requirement:
                    duration: const Duration(milliseconds: 200),
                    curve: Curves.decelerate,
                    child: InputField()),
              )
            ],
          )),
    );
  }
}

class InputField extends StatefulWidget {
  InputField({Key key}) : super(key: key);

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

class _InputFieldState extends State<InputField> {
  @override
  Widget build(BuildContext context) {
    return Container(
      color: Colors.grey[100],
      padding: const EdgeInsets.symmetric(vertical: 6),
      child: Row(
        children: [
          SizedBox(
            width: 60,
            child: Icon(Icons.add_a_photo),
          ),
          Flexible(
            child: TextField(
              style: Theme.of(context).textTheme.bodyText1,
              decoration: InputDecoration(
                border: InputBorder.none,
                hintText: 'Enter text...',
              ),
            ),
          ),
          SizedBox(
            width: 60,
            child: Icon(Icons.send),
          ),
        ],
      ),
    );
  }
}

输出 -> enter image description here

答案 2 :(得分:0)

您可以使用此程序包keyboard_visibility并收听keyboard visibility。然后,您可以给出实现功能的逻辑,就像可以缩短起始container的高度一样。那不是完美的。但是我认为这是目前的唯一方法。

答案 3 :(得分:0)

我使用类似的东西:

AnimatedPadding(
        padding: MediaQuery.of(context).viewInsets,
        duration: const Duration(milliseconds: 100),
        curve: Curves.decelerate,
        child: ....
    )

这会根据 viewInsets(软件键盘高度)为 padding 设置动画。

答案 4 :(得分:0)

您需要使用 keyboard_visibility 包并使用它来触发您的 AnimatedContainer 或 AnimatedPadding

bool _isKeyboardActive = false;
@override
void initState() {
  super.initState();
  //add keyboard visibility Listener
  KeyboardVisibility.onChange.listen((event) {
    setState(() {
      _isKeyboardActive = event;
    });
  });
}


Widget build(BuildContext context){
    return AnimatedContainer(
       width: _isKeyboardActive ? 200 : MediaQuery.of(context).size.width,
       height: 60,
       color: Colors.red,
       duration: Duration(milliseconds: 600)
    )
}

以此为基础。

答案 5 :(得分:-1)

您应该尝试像这样设置resizeToAvoidBottomPadding: false

return Scaffold(
      key: _scaffoldKey,
      resizeToAvoidBottomPadding: false,