简体   繁体   English

TextField 小部件失去焦点 (Flutter)

[英]TextField widgets lose focus (Flutter)

I am creating an app with Flutter TextField widgets:我正在使用 Flutter TextField小部件创建一个应用程序:

class CategoryData {
  int? id;
  String name;
  String description;

  CategoryData({this.id, required this.name, required this.description});
}

class CategoriesEdit extends StatefulWidget {
  Database? db;
  CategoryData? category;

  CategoriesEdit({super.key, required this.db, required this.category});

  @override
  State<StatefulWidget> createState() => CategoriesEditState();
}

class CategoriesEditState extends State<CategoriesEdit> {
  CategoryData? category;

  void saveState(BuildContext context) {
    // ...
  }

  @override
  Widget build(BuildContext context) {
    if (category == null) {
      setState(() {
        category = widget.category ?? CategoryData(name: "", description: "");
      });
    }

    return Scaffold(
        appBar: AppBar(
          leading: InkWell(
              child: const Icon(Icons.arrow_circle_left),
              onTap: () => Navigator.pop(context)),
          title: const Text("Edit Category"),
        ),
        body: Column(children: [
          Column(key: const Key('name'), children: [
            const Text("Category name:*"),
            TextField(
                controller: TextEditingController(text: category!.name),
                onChanged: (value) {
                  setState(() {
                    category!.name = value;
                  });
                })
          ]),
          Column(key: const Key('description'), children: [
            const Text("Description:"),
            TextField(
                controller: TextEditingController(text: category!.description),
                onChanged: (value) {
                  setState(() {
                    category!.description = value;
                  });
                })
          ]),
          Row(mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [
            ElevatedButton(
              onPressed: () => saveState(context), // passing false
              child: const Text('OK'),
            ),
            OutlinedButton(
              onPressed: () => Navigator.pop(context, false),
              // passing false
              child: const Text('Cancel'),
            ),
          ]),
        ]));
  }
}

But after I type a character in one of these two widgets, the cursor moves before the first character and the Android keyboard widget disappears.但是在我在这两个小部件中的一个中键入一个字符后,cursor 移动到第一个字符之前,并且 Android 键盘小部件消失了。 Why?为什么? And how to fix that bug?以及如何修复该错误?

I tried adding widget keys, but as you see it didn't help.我尝试添加小部件键,但如您所见,它没有帮助。

You do not have to do你不必做

controller: TextEditingController(text: category..name) controller:TextEditingController(文本:类别..名称)

because the controller's text automatically changes once you connect it to TextField.因为一旦您将控制器的文本连接到 TextField,控制器的文本就会自动更改。

The reason is once you set some text to the controller, it re-applies the text thus moving the cursor to the front.原因是一旦您为 controller 设置了一些文本,它就会重新应用文本,从而将 cursor 移到前面。

I have solved this for you:我已经为你解决了这个问题:

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

class CategoryData {
  int? id;
  String name;
  String description;

  CategoryData({this.id, required this.name, required this.description});
}

class CategoriesEdit extends StatefulWidget {
  CategoryData? category;

  CategoriesEdit({required this.category});

  @override
  State<StatefulWidget> createState() => CategoriesEditState();
}

class CategoriesEditState extends State<CategoriesEdit> {
  CategoryData? category;
  // Database? db;
  TextEditingController nametextController =  TextEditingController();
  TextEditingController descriptionTextController = TextEditingController();
  void saveState(BuildContext context) {
    // ...
  }

  @override
  Widget build(BuildContext context) {
    if (category == null) {
      setState(() {
        category = widget.category ?? CategoryData(name: "", description: "");
      });


    }
    nametextController.text = category!.name??"";
    descriptionTextController.text = category!.description??"";



    return Scaffold(
        appBar: AppBar(
          leading: InkWell(
              child: const Icon(Icons.arrow_circle_left),
              onTap: () => Navigator.pop(context)),
          title: const Text("Edit Category"),
        ),
        body: Column(children: [
          Column(key: const Key('name'), children: [
            const Text("Category name:*"),
            TextField(
                controller: nametextController,
                onChanged: (value) {
                  setState(() {
                    category!.name = value;
                  });
                })
          ]),
          Column(key: const Key('description'), children: [
            const Text("Description:"),
            TextField(
                controller: descriptionTextController,
                onChanged: (value) {
                  setState(() {
                    category!.description = value;
                  });
                })
          ]),
          Row(mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [
            ElevatedButton(
              onPressed: () => saveState(context), // passing false
              child: const Text('OK'),
            ),
            OutlinedButton(
              onPressed: () => Navigator.pop(context, false),
              // passing false
              child: const Text('Cancel'),
            ),
          ]),
        ]));
  }
}

I have tested this code and it is working fine, let me know if you have any doubt.我已经测试了这段代码,它工作正常,如果您有任何疑问,请告诉我。 Hope this helps you.希望这对您有所帮助。

There is a lot of things going wrong here, not only the stuff mentioned in the other answer.这里有很多问题,不仅仅是另一个答案中提到的东西。

  1. Move the setState in the builder into initState:将构建器中的 setState 移动到 initState 中:

     if (category == null) { setState(() { category = widget.category?? CategoryData(name: "", description: ""); }); }
  2. Don't use setState in the onChanged callback.不要在onChanged回调中使用setState Change:改变:

     onChanged: (value) { setState(() { category.;description = value; }); }

    to this:对此:

     onChanged: (value) { category.;description = value; }
  3. Store the TextEditingController s, because you have to dispose them once we dispose the state.存储TextEditingController ,因为一旦我们处置 state,您就必须处置它们。

  4. If you are already using TextEditingController s, then you don't need the onChanged callback.如果您已经在使用TextEditingController ,则不需要onChanged回调。 Just take text from the controller like explained in the other answer.只需从 controller 中获取文本,如其他答案中所述。

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

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