web-dev-qa-db-ja.com

TextField選択後のウィジェットの再構築Flutter

フォームが必要なFlutterアプリを開発しています。したがって、ユーザーがアプリを開くと、次のコードを持つフォームの前にスプラッシュスクリーンが表示されます。

import 'package:flutter/material.Dart';
import '../model/User.Dart';
import './FileManager.Dart';
import './MyListPage.Dart';

class UserLoader extends StatefulWidget {
  @override
  _UserLoaderState createState() => new _UserLoaderState();
}

class _UserLoaderState extends State<UserLoader> {
  final userFileName = "user_infos.txt";
  User _user;

  @override
  Widget build(BuildContext context) {
    print("build UserLoader");
    final _formKey = new GlobalKey<FormState>();
    final _firstNameController = new TextEditingController();
    final _lastNameController = new TextEditingController();
    final _emailController = new TextEditingController();
    final _phoneController = new TextEditingController();

    return new Scaffold(
        appBar: new AppBar(
          title: new Text("Informations"),
          actions: <Widget>[
            new IconButton(
                icon: const Icon(Icons.save),
                onPressed: () {
                  _user = _onFormValidate(
                      _formKey.currentState,
                      _firstNameController.text,
                      _lastNameController.text,
                      _emailController.text,
                      _phoneController.text);
                })
          ],
        ),
        body: new Center(
          child: new SingleChildScrollView(
              child: new Form(
                  key: _formKey,
                  child: new Column(children: <Widget>[
                    new ListTile(
                      leading: const Icon(Icons.person),
                      title: new TextFormField(
                        decoration: new InputDecoration(
                          hintText: "Prénom",
                        ),
                        keyboardType: TextInputType.text,
                        controller: _firstNameController,
                        validator: _validateName,
                      ),
                    ),
                    new ListTile(
                      leading: const Icon(Icons.person),
                      title: new TextFormField(
                        decoration: new InputDecoration(
                          hintText: "Nom",
                        ),
                        keyboardType: TextInputType.text,
                        controller: _lastNameController,
                        validator: _validateName,
                      ),
                    ),
Etc, etc ...

ただし、TextFieldをタップすると、キーボードが表示されてすぐに閉じ、すべてのコンポーネントが再構築されます。そのため、フォームに記入することはできません。

誰かが解決策を手に入れられますか?前もって感謝します !

11
Nadox56

このためのコード全体を提供していないため、コンテキストが何であるかわかりません。

私自身が陥った1つの落とし穴(そして、私があなたの説明から収集したように、あなたに影響を与えているかもしれません)は、ステートフルウィジェットが別のステートフルウィジェット内にネストされていることです。

例えば、

_class Parent extends StatefulWidget {
  @override
  ParentState createState() => ParentState();

  (...)
}

class ParentState extends State<Parent> {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
        body: Child(),
    );
  }

  (...)
}

class Child extends StatefulWidget {
  @override
  ChildState createState() => ChildState();

  (...)
}

class ChildState extends State<Child> {
  @override
  Widget build(BuildContext context) {
    return TextField(...);
  }

  (...)
}
_

ここでの問題は、親の再構築がParentState().build()が実行され、新しいChildnewChildStateインスタンスが作成されることを意味しますオブジェクト。すべてをリセットします。

ChildWidgetを再作成せずに、ParentStateに保存してみてください。

_class Parent extends StatefulWidget {
  @override
  ParentState createState() => ParentState();

  (...)
}

class ParentState extends State<Parent> {
  Child _child;

  @override
  void initState() {
    _child = Child();
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
        body: child,
    );
  }

  (...)
}
// The rest remains the same
_

編集:ウィジェットツリーがもう少し複雑な場合は、1)親からのコールバックを渡して状態の変化を通知する必要があること、2)setState()を呼び出すことも忘れないでください。子。

12
rbp

新しいクラスを作成し、問題が発生したターゲットクラスにインポートするだけです。例えば ​​:

私は通常、次のようなクラスを作成します。

class MiddleWare
{
  static MiddleWare shared = MiddleWare();
  _MiddleWare(){}
  String myText = "my Text";
  // every variables should be here...
}

そして

import "MiddleWare.Dart";

class myclass extends StatefulWidget {
  @override
  _myclassState createState() => _myclassState();
}

class _myclassState extends State<myclass> {
  @override
  Widget build(BuildContext context) {
    return Container(child: Text(MiddleWare.shared.myText));
  }
}

それでおしまい。

1

このようなコンテキストを受け取る関数を作成してみてください

class YourPage extends StatefulWidget {
  const YourPage(Key key) : super(key: key);

  static Future<void> show({ BuildContext context,}) async {
     await Navigator.of(context, rootNavigator: true).Push(
         MaterialPageRoute(
    builder: (context) => YourPage()
    );}

   @override
   _YourPageState createState() => _YourPageState();
}
......YourPage Build.....

次に、ページにコンテキストを提供します。再構築すると、親の再構築を妨げるコアコンテキストが含まれます。

onPressed: () async {
             await YourPage.show(context: context);