Даже после прочтения этого и этого , я все еще не могу осмыслить сохранение состояний страниц во Flutter.
Я создал пример приложения, у которого есть главная страница с именем MyHomePage
и вторая страница с именем SecondPage
. MyHomePage
имеет плавающую кнопку действия, которая отображает SecondPage
через Navigator.push(...)
. Вторая страница содержит текстовое поле с назначенным контроллером. Я хотел бы сохранить текст текстового поля после того, как я закрою и снова открою SecondPage
.
Я пробовал всевозможные комбинации с настройками сегментов, состояний страниц и ключей (вдохновленных ссылками выше), но я не мог заставить его работать.
Также я хотел бы сохранить состояние всей страницы автоматически - без необходимости писать / извлекать каждое отдельное значение вручную (в случае, если у меня много текстовых полей на странице ).
Вот мой код:
import 'package:flutter/material.dart';
void main() => runApp(MyApp());
PageStorageKey mykey = new PageStorageKey("testkey");
class MyApp extends StatelessWidget {
final PageStorageBucket _bucket = new PageStorageBucket();
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: PageStorage(
bucket: _bucket,
child: MyHomePage(),
)
);
}
}
class MyHomePage extends StatefulWidget {
MyHomePage({Key key}) : super(key: key);
@override
_MyHomePageState createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text("State demo"),
),
body: Center(
child: Column(
children: <Widget>[
],
),
),
floatingActionButton: FloatingActionButton(
onPressed: _openSecondPage,
tooltip: 'Increment',
child: Icon(Icons.add),
),
);
}
_openSecondPage() {
Navigator.push(context, new MaterialPageRoute(builder: (context) => new SecondPage()));
}
}
class SecondPage extends StatefulWidget {
@override
_SecondPageState createState() => _SecondPageState();
}
class _SecondPageState extends State<SecondPage> {
final _aController = TextEditingController();
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text("Second page"),
),
body: Center(
child: TextField(
controller: _aController,
key: mykey,
autofocus: true,
),
)
);
}
}
EDIT:
Основываясь на ответе Аджая, я смог значительно упростить рабочий код . Оказывается, что для сохранения состояний виджета вручную все, что вам нужно, это экземпляр PageStorageBucket
в сочетании с ValueKey
экземплярами.
Вот изменения, которые я внес в код Ajay:
- Удален плагин after_layout (достаточно метода
initState
). - Удален глобальный экземпляр
PageStorageKey
(заменен локальным экземпляром ValueKey
на странице, которая должна его использовать). - Удален глобальный экземпляр
PageStorageBucket
и заменен последним экземпляром из MyApp
, который передается на страницы, которым он нужен, через атрибуты конструктора. - Удалено
PageStorage
из дерева компонентов.
Вот полученный код (простейшая рабочая форма):
import 'package:flutter/material.dart';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
final bucket = PageStorageBucket();
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: MyHomePage(bucket: bucket,),
);
}
}
class MyHomePage extends StatefulWidget {
final PageStorageBucket bucket;
const MyHomePage({Key key, this.bucket}) : super(key: key);
@override
_MyHomePageState createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text("State demo"),
),
body: Center(
child: Column(
children: <Widget>[],
),
),
floatingActionButton: FloatingActionButton(
onPressed: _openSecondPage,
tooltip: 'Increment',
child: Icon(Icons.add),
),
);
}
_openSecondPage() {
Navigator.push(
context, new MaterialPageRoute(builder: (context) => new SecondPage(bucket: widget.bucket,)));
}
}
class SecondPage extends StatefulWidget {
final PageStorageBucket bucket;
const SecondPage({Key key, this.bucket}) : super(key: key);
@override
_SecondPageState createState() => _SecondPageState();
}
class _SecondPageState extends State<SecondPage> {
static const KEY_A = ValueKey("secondPage.A");
final _aController = TextEditingController();
@override
void initState() {
super.initState();
_aController.addListener(_updateValue);
String value = widget.bucket.readState(context, identifier: KEY_A) ?? "";
_aController.text = value;
}
_updateValue() {
widget.bucket.writeState(context, _aController.text, identifier: KEY_A);
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text("Second page"),
),
body: Center(
child: TextField(
controller: _aController,
autofocus: true,
),
),
);
}
}