【问题标题】:Widgets don't build when soft keyboard closes软键盘关闭时不构建小部件
【发布时间】:2021-06-07 15:50:02
【问题描述】:

第一次观看the short video clip of the app。请注意 sliver 应用栏底部右侧的照片图标按钮。它在向上滚动时缩小/淡化,并在向下滚动时反转。但是,请注意,当我打开键盘,然后关闭键盘时,照片图标按钮不会返回。这是因为小部件没有构建,因此计算该按钮的大小、不透明度和位置的代码永远不会运行。我不知道如何在软键盘关闭时触发小部件的构建。

视频链接:https://drive.google.com/file/d/1YVlvBDYB3EQVpwdMVSIvLaAeWK_VeQCE/view?usp=sharing

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

class TestDetailsScreen extends StatefulWidget {
  static final String routeName = '/test-details-screen';

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

class _TestDetailsScreenState extends State<TestDetailsScreen>
    with SingleTickerProviderStateMixin {
  ScrollController _scrollController;
  AnimationController _animationController;
  Animation _animation;

  @override
  void initState() {
    super.initState();
    _scrollController = new ScrollController();
    _scrollController.addListener(() => setState(() {}));
    _animationController = AnimationController(
      duration: Duration(milliseconds: 250),
      vsync: this,
    );

    _animation = Tween(begin: 1.0, end: 0.0).animate(_animationController);
  }

  @override
  void dispose() {
    _scrollController.dispose();
    super.dispose();
  }

  @override
  Widget build(BuildContext context) {
    final double defaultTopMargin = 190.0 - 4.0;
    double top = defaultTopMargin;

    if (_scrollController.hasClients) {
      double offset = _scrollController.offset;
      top -= offset;
    }

    if (top <= 75.0 && _animation.isDismissed) {
      _animationController.forward();
    } else if (top >= 75.0 && _animation.isCompleted) {
      _animationController.reverse();
    }

    return Scaffold(
      body: Stack(
        children: [
          CustomScrollView(
            controller: _scrollController,
            slivers: [
              SliverAppBar(
                pinned: true,
                floating: false,
                expandedHeight: 190.0,
                iconTheme: IconThemeData(
                  color: Theme.of(context).primaryColorLight,
                ),
                flexibleSpace: FlexibleSpaceBar(
                  title: Text(
                    'Add inputs',
                    style: TextStyle(
                      color: Theme.of(context).primaryColorLight,
                      fontSize: 16.0,
                    ),
                  ),
                  background: Image.asset(
                    'assets/images/clouds.jpg',
                    fit: BoxFit.cover,
                  ),
                ),
                actions: [
                  IconButton(
                    icon: const Icon(Icons.check),
                    onPressed: () {},
                  ),
                ],
              ),
              SliverList(
                delegate: SliverChildListDelegate.fixed([
                  Padding(
                    padding: const EdgeInsets.only(left: 10, right: 10),
                    child: SizedBox(
                      width: double.infinity,
                      child: Column(
                        children: [
                          Padding(
                            padding: const EdgeInsets.only(top: 25),
                            child: Card(
                              color: Theme.of(context).primaryColorLight,
                              shape: RoundedRectangleBorder(
                                borderRadius: BorderRadius.circular(5),
                              ),
                              elevation: 0,
                              margin: EdgeInsets.all(5),
                              child: Padding(
                                padding: const EdgeInsets.all(20.0),
                                child: Column(
                                  children: [
                                    TextFormField(
                                      decoration: const InputDecoration(
                                        border: const UnderlineInputBorder(),
                                        labelText: 'Your text',
                                      ),
                                    ),
                                    TextFormField(
                                      decoration: const InputDecoration(
                                        border: const UnderlineInputBorder(),
                                        labelText: 'Your text',
                                      ),
                                    ),
                                  ],
                                ),
                              ),
                            ),
                          ),
                          Padding(
                            padding: const EdgeInsets.only(top: 10),
                            child: Card(
                              color: Theme.of(context).primaryColorLight,
                              shape: RoundedRectangleBorder(
                                borderRadius: BorderRadius.circular(5),
                              ),
                              elevation: 0,
                              margin: const EdgeInsets.all(5),
                              child: Padding(
                                padding: const EdgeInsets.all(20.0),
                                child: Column(
                                  children: [
                                    Align(
                                      alignment: Alignment.topLeft,
                                      child: const Text(
                                        'Additional Details (Optional)',
                                      ),
                                    ),
                                    Row(
                                      children: [
                                        Expanded(
                                          child: TextFormField(
                                            decoration: const InputDecoration(
                                              border:
                                                  const UnderlineInputBorder(),
                                              labelText: 'Your text',
                                            ),
                                          ),
                                        ),
                                        Padding(
                                          padding: const EdgeInsets.all(
                                            10,
                                          ),
                                        ),
                                        Expanded(
                                          child: TextFormField(
                                            decoration: const InputDecoration(
                                              border:
                                                  const UnderlineInputBorder(),
                                              labelText: 'Your text',
                                            ),
                                          ),
                                        ),
                                      ],
                                    ),
                                    Row(
                                      children: [
                                        Expanded(
                                          child: TextFormField(
                                            decoration: InputDecoration(
                                              border:
                                                  const UnderlineInputBorder(),
                                              labelText: 'Your text',
                                              hintStyle: Theme.of(context)
                                                  .textTheme
                                                  .caption,
                                            ),
                                          ),
                                        ),
                                        Padding(
                                          padding: EdgeInsets.all(
                                            10,
                                          ),
                                        ),
                                        Expanded(
                                          child: TextFormField(
                                            maxLength: 4,
                                            keyboardType: TextInputType.number,
                                            decoration: const InputDecoration(
                                              border:
                                                  const UnderlineInputBorder(),
                                              labelText: 'Your text',
                                              counterText: '',
                                            ),
                                          ),
                                        ),
                                      ],
                                    ),
                                    Row(
                                      children: [
                                        Expanded(
                                          child: TextFormField(
                                            inputFormatters: [
                                              FilteringTextInputFormatter.allow(
                                                  RegExp('[a-zA-Z]'))
                                            ],
                                            decoration: const InputDecoration(
                                              border:
                                                  const UnderlineInputBorder(),
                                              labelText: 'Your text',
                                              counterText: '',
                                            ),
                                          ),
                                        ),
                                        Padding(
                                          padding: EdgeInsets.all(
                                            10,
                                          ),
                                        ),
                                        Expanded(
                                          child: FractionallySizedBox(
                                            alignment: Alignment.centerLeft,
                                            child: TextFormField(
                                              keyboardType:
                                                  TextInputType.number,
                                              decoration: InputDecoration(
                                                alignLabelWithHint: false,
                                                border:
                                                    const UnderlineInputBorder(),
                                                labelText: 'Your choices',
                                                labelStyle: const TextStyle(
                                                  height: 1,
                                                ),
                                                suffix: const Text(
                                                  'Measurement',
                                                  style: const TextStyle(
                                                    fontSize: 16,
                                                  ),
                                                ),
                                              ),
                                            ),
                                          ),
                                        ),
                                      ],
                                    ),
                                  ],
                                ),
                              ),
                            ),
                          ),
                          Row(
                            children: [
                              Expanded(
                                child: IconButton(
                                  icon: Icon(
                                    Icons.archive,
                                    color: Theme.of(context).primaryColorDark,
                                  ),
                                  onPressed: () {},
                                ),
                              ),
                              Expanded(
                                child: IconButton(
                                  icon: Icon(
                                    Icons.delete,
                                    color: Theme.of(context).primaryColorDark,
                                  ),
                                  onPressed: () {},
                                ),
                              )
                            ],
                          )
                        ],
                      ),
                    ),
                  ),
                ]),
              )
            ],
          ),
          AnimatedBuilder(
            animation: _animation,
            builder: (BuildContext context, Widget child) {
              return Positioned(
                top: top <= 50 ? 50 : top,
                right: 16.0,
                child: new Transform(
                  transform: new Matrix4.identity()..scale(_animation.value),
                  alignment: Alignment.center,
                  child: Opacity(
                    opacity: _animation.value,
                    child: new FloatingActionButton(
                      elevation: 0,
                      backgroundColor: Theme.of(context).primaryColorDark,
                      onPressed: () => {},
                      child: new Icon(
                        Icons.photo,
                        color: Theme.of(context).primaryColorLight,
                      ),
                    ),
                  ),
                ),
              );
            },
          )
        ],
      ),
    );
  }
}

【问题讨论】:

  • 问题是两件事 - 键盘关闭时不会构建小部件树,因为没有任何引用 MediaQuery.of(context).viewInsets 如果您添加对此的引用,甚至将变量设置为在 build 方法的顶部,当 mediaquery 的 viewInsets 改变时,widget 树会重建。然而,下一个问题是在键盘关闭后滚动控制器的偏移值保持不变,即使它应该恢复为 0。

标签: android flutter dart flutter-layout flutter-animation


【解决方案1】:

您可以使用这个包来了解键盘是否可见。 https://pub.dev/packages/flutter_keyboard_visibility

【讨论】:

  • 我试过了,没有覆盖用户使用手机底部软键关闭键盘的情况。
  • 您必须使用逻辑来检查键盘是否不可见,然后设置状态以触发重建。该软件包不会自动重建您的树。在 Android 上,如果用户点击软后退按钮,此包会为 isKeyboardVisible 触发 false。
猜你喜欢
  • 2019-10-12
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-12-09
  • 1970-01-01
  • 2023-03-07
  • 2021-07-23
  • 1970-01-01
相关资源
最近更新 更多