Почему Flutter перерисовывает виджет, который содержит TextFormField с собственным ключом? - PullRequest
0 голосов
/ 07 февраля 2019


    Doctor summary (to see all details, run flutter doctor -v):
    [v] Flutter (Channel dev, v1.2.0, on Microsoft Windows [Version 10.0.17763.253], locale ru-RU)
    [v] Android toolchain - develop for Android devices (Android SDK version 28.0.3)
    [v] Android Studio (version 3.3)
    [v] VS Code, 64-bit edition (version 1.30.2)
    [v] Connected device (1 available)

    • No issues found!

Привет!Я изучаю флаттер дома, чтобы создать свое приложение, и столкнулся с непонятностью флаттера - когда я создаю форму с полями в любом виджете на любом маршруте навигатора, я видел перестроение этого маршрута при нажатии на поле формы и при закрытии клавиатуры.Если я удаляю GlobalKey и удаляю GlobalKey - виджет перестраивается при нажатии и скрывается клавиатура до сих пор, и в этой ситуации это не вызывает дискомфорта, но если я хочу наделить форму и эти поля глобальными ключами - при любом взаимодействии с полями, я вижу, что форма разрушает истроить снова и снова.



    import 'package:flutter/material.dart';
    import 'package:flutter_mobx/flutter_mobx.dart';
    import 'package:quich/controllers/user_controller.dart';
    import 'package:quich/route/routes.dart';
    import 'package:quich/screens/login_screen.dart';
    import 'package:quich/screens/splash_screen.dart';
    import 'package:quich/store/app_store.dart';

    void main() async {
      runApp(Quich());
      await $store.storage.ready;
      var uc = UserController();
      var isValid = await uc.isTokenValid(token: 'token');
      $store.isAuth = isValid;
      $store.isLoading = false;
    }

    class Quich extends StatefulWidget {
      @override
      State createState() => _QuichState();
    }

    class _QuichState extends State {
      final controller = TextEditingController();
      @override
      Widget build(BuildContext context) {
        return MaterialApp(
          title: 'Регистрация',
          theme: ThemeData(
            primarySwatch: Colors.blue,
          ),
          initialRoute: Routes.splash,
          routes: {
            Routes.splash: (context) => Observer(builder: (_) {
              return SplashScreen();
            }),
            Routes.login: (context) {
              print('SUPER PARENT BUILD');
              return LoginScreen();
              final formKey = GlobalKey();
              final fieldKey = GlobalKey();
              return Scaffold(
                body: Column(
                  mainAxisAlignment: MainAxisAlignment.center,
                  children: [
                    Form(
                      child: Padding(
                        padding: const EdgeInsets.all(15.0),
                        child: TextFormField(
                          controller: controller,
                          key: fieldKey
                        ),
                      ),
                      key: formKey,
                    ),
                    ButtonBar(
                      children: [
                        MaterialButton(
                          child: Text('Проверка', style: TextStyle(color: Colors.white)),
                          onPressed: () => Navigator.of(context).pushNamed(Routes.splash),
                          color: Colors.lightBlue,
                        )
                      ],
                    )
                  ],
                ),
              );
            }
          },
        );
      }
    }

Может ли кто-нибудь помочь мне создать форму с полями с глобальными ключами внутри Navigator - я искал примеры с формами и навигацией, но формы с глобальными ключами в навигаторах не найдены мной;

UPD: Кажется, что редактор кода StackOverflow "ест" определения типов некоторых частей кода.Я прилагаю изображение с кодом, и, пожалуйста, смотрите примеры видео:

Видео 1

Видео 2

Изображение с кодом

Ru-копия этой темы

PS Проблема решена, решение этой проблемы, если вам интересно - можете посмотреть на "PPS""Блок русскоязычной копии этого вопроса: Русская копия

Ответы [ 2 ]

0 голосов
/ 07 февраля 2019

Я заметил, что вы не использовали правильный общий способ расширения классов,

 class _QuichState extends State<Quich>{}

Попробуйте это, затем я дам вам пример кода, чтобы вы могли сопоставить свой код с

   return Form(
  key: _formKey,
  child: Column(
    crossAxisAlignment: CrossAxisAlignment.start,
    children: <Widget>[
      TextFormField(
        validator: (value) {
          if (value.isEmpty) {
            return 'Please enter some text';
          }
        },
      ),
      Padding(
        padding: const EdgeInsets.symmetric(vertical: 16.0),
        child: RaisedButton(
          onPressed: () {
            // Validate will return true if the form is valid, or false if
            // the form is invalid.
            if (_formKey.currentState.validate()) {
              // If the form is valid, we want to show a Snackbar
              Scaffold.of(context)
                  .showSnackBar(SnackBar(content: Text('Processing Data')));
            }
          },
          child: Text('Submit'),
        ),
      ),
    ],
  ),
);

После этого создайте глобальный ключ, который будет однозначно идентифицировать виджет «Форма» и позволит нам проверять форму или другие действия

Примечание. Это GlobalKey, а не GlobalKey!

  final _formKey = GlobalKey<FormState>();
0 голосов
/ 07 февраля 2019

В флаттере key атрибут используется для сравнения существующего экземпляра виджета с новым экземпляром и решения, что делать дальше: создать новое состояние или использовать существующее состояние, построить новое поддерево или повторно использовать существующее.Если ключ не указан, флаттер будет использовать местоположение виджета в дереве виджетов в качестве ключа.Если древовидная структура не изменилась слишком сильно, вполне вероятно, что состояние или поддерево будет повторно использовано, если есть только небольшое изменение.

Идея GlobalKey() будет состоять в том, что вы создадите один его экземпляр искорее всего, сохраните его где-нибудь очень высоко в иерархии дерева приложений.

С помощью GlobalKey() можно повторно использовать состояние и поддерево виджета, если:

  • вы сохраняете то же самоеэкземпляр GlobalKey()
  • ваш виджет не полностью удален из дерева.Если виджет удален, его состояние и поддерево исчезнут, и в следующий раз, когда он войдет в древовидное состояние вашего приложения, поддерево будет воссоздано.

В вашем примере кода вы не назначаете GlobalKey() длямногоразовая переменная.В вашем случае новый экземпляр Globalkey() создается внутри вашей функции сборки.Это приводит к созданию нового уникального ключа при каждом обновлении.Новый уникальный ключ означает, что виджет не связан с предыдущим экземпляром виджета, поэтому состояние и поддерево не переносятся.

...