简体   繁体   English

键盘覆盖文本字段,Flutter 中的 focusNode 不起作用

[英]Keyboard overlay textfield, not working focusNode in Flutter

I have a text field on the page which is located at the very bottom.我在页面的最底部有一个文本字段。 resizeToAvoidBottomInset value: false . resizeToAvoidBottomInset value: false I added a focuseNode so that when the field is clicked, it will be in focus.我添加了一个focuseNode ,以便在单击该字段时,它会处于焦点状态。 But when I click on this text field, the keyboard overlaps and nothing is visible because the text field is at the very bottom and the page does not scroll when the keyboard opens.但是,当我单击此文本字段时,键盘重叠并且看不到任何内容,因为文本字段位于最底部,并且当键盘打开时页面不会滚动。 How can I make the text field visible when opening the keyboard?打开键盘时如何使文本字段可见? If I use resizeToAvoidBottomInset: true , then the page scrolls, but between the keyboard and the widget there is a large padding that is set at the bottom of the page and I cannot remove this padding.如果我使用resizeToAvoidBottomInset: true ,那么页面会滚动,但在键盘和小部件之间,页面底部设置了一个大填充,我无法删除此填充。

main page主页

const Scaffold(
        resizeToAvoidBottomInset: false,
        body: FormPage(),
      ),

body身体

class FormPage extends StatefulWidget {
  final int? paid;
  final bool? init;
  final Function(bool) parking;
  final Function(int) valueChange;
  const PaidParking({
    Key? key,
    required this.parking,
    required this.paid,
    required this.init,
    required this.valueChange,
  }) : super(key: key);

  @override
  State<FormPage > createState() => _FormPageState();
}

class _FormPageState extends State<FormPage > {
  FocusNode myFocusNodeName = FocusNode();

  final TextEditingController controller =
      TextEditingController(text: '€59 per h');

  @override
  void initState() {
    setState(() {
      paidParking = widget.parkingInit ?? false;
      controller.text =
          '€${widget.paidInit != null ? (widget.paidInit! / 100) : 2} per h';
    });
    super.initState();
  }

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

    myFocusNodeName.dispose();
  }

  @override
  Widget build(BuildContext context) {
    myFocusNodeName.addListener(() {
      setState(() {});
    });
    return Padding(
      padding: const EdgeInsets.only(top: 15),
      child: Column(
        children: [
          Row(
            children: [
              Opacity(
                opacity: paidParking ? 1 : 0.7,
                child: const Text(
                  'Form Page',
                  style: TextStyle(
                    fontSize: 14,
                    fontFamily: constants.FontFamily.AvenirLtStd,
                    fontWeight: FontWeight.w700,
                  ),
                ),
              ),
              const SizedBox(width: 8),
              switcher,
            ],
          ),
          const SizedBox(height: 15),
          paidParking ? parkingValueGet() : const SizedBox(),
        ],
      ),
    );
  }

  void changeValue(bool operation, {bool editing = false}) {
    final String value = controller.text;

    double num = double.parse(
      value
          .replaceAll('€', '')
          .replaceAll('per', '')
          .replaceAll('h', '')
          .replaceAll(' ', ''),
    );

    if (!editing) {
      if (num <= 0 && !operation) return;

      operation ? num += 0.05 : num -= 0.05;
      controller.text = '€${num.toStringAsFixed(2)} per h';
      widget.paidValueChange((num * 100).round());
    } else {
      num = double.parse(controller.text);
      controller.text = '€${num.toStringAsFixed(2)} per h';
      num = double.parse(
        value
            .replaceAll('€', '')
            .replaceAll('per', '')
            .replaceAll('h', '')
            .replaceAll(' ', ''),
      );
      widget.valueChange((num * 100).round());
    }
  }

  Widget parkingValueGet() {
    return Row(
      mainAxisAlignment: MainAxisAlignment.center,
      crossAxisAlignment: CrossAxisAlignment.end,
      children: [
        InkWell(
          onTap: () => changeValue(false),
          child: _circleBox(false),
        ),
        Column(
          children: [
            SizedBox(
              height: 40,
              width: 120,
              child: TextField(
                controller: controller,
                focusNode: myFocusNodeName,
                style: const TextStyle(
                  fontSize: 16,
                  fontFamily: FontFamily.AvenirBook,
                  color: constants.Colors.white,
                  decoration: TextDecoration.none,
                ),
                onSubmitted: (value) => changeValue(true, editing: true),
                onEditingComplete: () => changeValue(true, editing: true),
                keyboardType: const TextInputType.numberWithOptions(
                  decimal: true,
                  signed: true,
                ),
                inputFormatters: [
                  FilteringTextInputFormatter.allow(RegExp(r"[0-9.]")),
                ],
                textAlign: TextAlign.center,
                decoration: const InputDecoration(
                  border: InputBorder.none,
                ),
              ),
            ),
            Container(color: Colors.white, height: 1, width: 115),
          ],
        ),
        InkWell(
          onTap: () => changeValue(true),
          child: _circleBox(true),
        ),
      ],
    );
  }

  Widget _circleBox(bool operation) {
    return Container(
      height: 23,
      width: 23,
      alignment: Alignment.center,
      decoration: BoxDecoration(
        shape: BoxShape.circle,
        border: Border.all(
          color: constants.Colors.white,
        ),
      ),
      child: Text(
        operation ? '+' : '-',
        style: constants.Styles.smallBoldTextStyleWhite,
      ),
    );
  }

  Widget get switcher => Opacity(
        opacity: paidParking ? 1 : 0.7,
        child: GestureDetector(
          onTap: () {
            setState(() {
              paidParking = !paidParking;
            });
            widget.paidParking(paidParking);
          },
          child: Container(
            height: 20,
            alignment:
                paidParking ? Alignment.centerRight : Alignment.centerLeft,
            width: 40,
            decoration: BoxDecoration(
              color: paidParking ? constants.Colors.purpleMain : Colors.white,
              borderRadius: BorderRadius.circular(14.5),
            ),
            child: Padding(
              padding: const EdgeInsets.symmetric(horizontal: 4),
              child: Container(
                height: 17,
                width: 17,
                decoration: BoxDecoration(
                  shape: BoxShape.circle,
                  color: paidParking ? Colors.white : const Color(0xff484452),
                ),
              ),
            ),
          ),
        ),
      );
}

First I can recommend you to do some changes.首先我可以建议你做一些改变。

  1. Remove setState() method calling inside initState() (have no effect).删除在initState()内部调用的setState()方法(无效)。

  2. Remove totally the part of the below code.完全删除以下代码的一部分。 When you are using TexField inside a StatefulWidget , every time the keyboard opened it will recall your build() method and in this case, will add multiple focus listeners on each build() method call, also each focus listener is calling the setState() method which is triggering build() method again.当您在StatefulWidget中使用TexField时,每次打开键盘时,它都会调用您的build()方法,在这种情况下,将在每个build()方法调用上添加多个焦点侦听器,同时每个焦点侦听器都在调用setState()再次触发build()方法的方法。 This is kind of an infinity loop.这是一种无限循环。 I wonder when you open the keyboard, does your app stuck or stop working smoothly?我想知道当您打开键盘时,您的应用程序是否卡住或停止运行?

    myFocusNodeName.addListener(() { setState(() {}); }); myFocusNodeName.addListener(() { setState(() {}); });

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

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