首页 > 解决方案 > Flutter:持久化页面状态

问题描述

即使在阅读了 thisthis之后,我似乎仍然无法在 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,
        ),
      )
    );
  }
}

编辑:

根据 Ajay 的回答,我能够大大简化工作代码。事实证明,为了手动保存小部件状态,您所需要的只是一个与实例PageStorageBucket相结合的ValueKey实例。

以下是我对 Ajay 的代码所做的修改:

这是生成的代码(最简单的工作形式):

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,
        ),
      ),
    );
  }
}

标签: flutter

解决方案


您还需要读取和写入状态。

演示

查看下面的代码。

注意:我使用after_layout来初始化文本控制器。

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

void main() => runApp(MyApp());

PageStorageKey mykey = new PageStorageKey("testkey");
final PageStorageBucket _bucket = new PageStorageBucket();

class MyApp extends StatelessWidget {
  @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>
    with AfterLayoutMixin<SecondPage> {
  final _aController = TextEditingController();

  @override
  void initState() {
    super.initState();
    _aController.addListener(_updateValue);
  }

  @override
  void afterFirstLayout(BuildContext context) {
    String value =
        _bucket.readState(context, identifier: ValueKey(mykey)) ?? "";
    print(value);
    _aController.text = value;
  }

  _updateValue() {
    _bucket.writeState(context, _aController.text, identifier: ValueKey(mykey));
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text("Second page"),
      ),
      body: Center(
        child: TextField(
          controller: _aController,
          key: mykey,
          autofocus: true,
        ),
      ),
    );
  }
}

推荐阅读