Почему Flutter перерисовывает виджет, который содержит TextFormField с собственным ключом?
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 - я искал примеры с формами и навигацией, но формы с globalKeys в навигаторах не найдены мной;
UPD: Кажется, что редактор кода Stackru "ест" определения типов некоторых частей кода. Я прилагаю изображение с кодом, и, пожалуйста, посмотрите примеры видео:
PS Проблема решена, решение этого, если вам интересно - можете посмотреть на "PPS" блок русскоязычной копии этого вопроса: Russian Copy
2 ответа
В трепетании key
Атрибут используется для сравнения существующего экземпляра виджета с новым экземпляром и определения того, что делать дальше: создать новое состояние или использовать существующее состояние, построить новое поддерево или повторно использовать существующее. Если ключ не указан, флаттер будет использовать местоположение виджета в дереве виджетов в качестве ключа. Если древовидная структура не сильно изменилась, вполне вероятно, что состояние или поддерево будет повторно использовано, если есть только небольшое изменение.
Идея о GlobalKey()
будет то, что вы создадите один его экземпляр и, скорее всего, сохраните его где-то очень высоко в иерархии дерева приложений.
С помощью GlobalKey()
можно повторно использовать состояние и поддерево виджета, если:
- вы держите тот же экземпляр
GlobalKey()
- Ваш виджет не полностью удален из дерева. Если виджет удален, его состояние и поддерево исчезнут, и в следующий раз, когда он войдет в древовидное состояние вашего приложения, поддерево будет воссоздано.
В вашем примере кода вы не назначаете GlobalKey()
к многоразовой переменной. В вашем случае новый экземпляр Globalkey()
создается внутри вашей функции сборки. Это приводит к созданию нового уникального ключа при каждом обновлении. Новый уникальный ключ означает, что виджет не связан с предыдущим экземпляром виджета, поэтому состояние и поддерево не переносятся.
Я заметил, что вы не использовали правильный общий способ в расширении классов,
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>();