Flutter自动存储输入内容插件self_storing_input的使用

Flutter 自动存储输入内容插件 self_storing_input 的使用

概述

self_storing_input 是一组自动保存和加载输入值到数据存储中的输入小部件。

示例演示

示例演示页面

使用方法

定义 Saver

首先,实现一个 Saver,用于加载、验证和保存数据项。itemKey 可以是任何形式,例如资源 URL 字符串或连接字符串、表、对象 ID 和列的元组。

示例代码:

class _DemoSaver with ChangeNotifier implements Saver<String> {
  Map<String, dynamic> storage = {};
  bool failSaving = false;
  Duration delay = const Duration(milliseconds: 100);

  [@override](/user/override)
  Future<T> load<T>(String itemKey) async {
    // 这个延迟是为了演示目的。
    await Future.delayed(delay);
    return storage[itemKey];
  }

  [@override](/user/override)
  OperationResult validate<T>(String itemKey, T value) {
    if (itemKey == Fields.phrase && (value?.toString()?.length ?? 0) % 2 == 1) {
      return OperationResult.error('Value should have even number of letters.');
    }
    return OperationResult.success();
  }

  [@override](/user/override)
  Future<OperationResult> save<T>(String itemKey, T value) async {
    // 这个延迟是为了演示目的。
    await Future.delayed(delay);
    if (failSaving) {
      return OperationResult.error('Failed to save the value, for demo purposes.');
    }
    storage[itemKey] = value;
    notifyListeners();
    return OperationResult.success();
  }
}
定义输入小部件

self_storing_input 小部件添加到屏幕,并用定义的 SaveritemKey 参数化每个小部件。这些小部件会处理加载数据、验证数据、保存数据以及处理诸如网络连接差和数据存储失败等故障模式。

关闭覆盖层

在屏幕状态中定义一个 OverlayController

OverlayController _controller = OverlayController();

将屏幕小部件主体包装在一个 GestureDetector 中,以便在点击时关闭编辑覆盖层:

GestureDetector(
  onTap: () async {
    _controller.close();
  },
  child: Scaffold(
    body: ...

_controller 传递给每个 self_storing 小部件:

SelfStoringText(
  overlayController: _controller,
  ...

完整示例代码

import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:self_storing_input/self_storing_input.dart';
import 'package:url_launcher/url_launcher.dart';

class Fields {
  static const String phrase = 'phrase';
  static const String paragraph = 'paragraph';
  static const String tristate = 'tristate';
  static const String twostate = 'twostate';
  static const String unselectableRadioGroup = 'unselectableRadioGroup';
  static const String radioGroup = 'radioGroup';
}

class _DemoSaver with ChangeNotifier implements Saver<String> {
  Map<String, dynamic> storage = {};
  bool failSaving = false;
  Duration delay = const Duration(milliseconds: 100);

  [@override](/user/override)
  Future<T> load<T>(String itemKey) async {
    await Future.delayed(delay);
    return storage[itemKey];
  }

  [@override](/user/override)
  OperationResult validate<T>(String itemKey, T value) {
    if (itemKey == Fields.phrase && (value?.toString()?.length ?? 0) % 2 == 1) {
      return OperationResult.error('Value should have even number of letters.');
    }
    return OperationResult.success();
  }

  [@override](/user/override)
  Future<OperationResult> save<T>(String itemKey, T value) async {
    await Future.delayed(delay);
    if (failSaving) {
      return OperationResult.error('Failed to save the value, for demo purposes.');
    }
    storage[itemKey] = value;
    notifyListeners();
    return OperationResult.success();
  }
}

void main() {
  runApp(Demo());
}

class Demo extends StatefulWidget {
  [@override](/user/override)
  _DemoState createState() => _DemoState();
}

class _DemoState extends State<Demo> {
  OverlayController _controller = OverlayController();
  final _DemoSaver _saver = _DemoSaver();

  [@override](/user/override)
  void initState() {
    _saver.addListener(() => setState(() {}));
    super.initState();
  }

  [@override](/user/override)
  Widget build(BuildContext context) {
    return MaterialApp(
      home: GestureDetector(
        onTap: () async {
          _controller.close();
        },
        child: Scaffold(
          body: SingleChildScrollView(
            child: ListTileTheme(
              contentPadding: EdgeInsets.all(0),
              child: Padding(
                padding: EdgeInsets.all(40),
                child: Column(
                  crossAxisAlignment: CrossAxisAlignment.start,
                  children: [
                    _section('SELF_STORING_INPUT\nDEMO', buildDemoHeader()),
                    _section('Demo Parameters', buildDemoParameters()),
                    Row(
                      crossAxisAlignment: CrossAxisAlignment.start,
                      children: [
                        _section('Self Storing Input Widgets', buildDemo()),
                        if (_saver.storage.isNotEmpty)
                          _section('Storage Content', buildStorageObserver()),
                      ],
                    )
                  ],
                ),
              ),
            ),
          ),
        ),
      ),
    );
  }

  static Widget _right(List<Widget> widgets) {
    return Padding(
      child: Column(crossAxisAlignment: CrossAxisAlignment.start, children: widgets),
      padding: EdgeInsets.only(left: 20),
    );
  }

  Widget _section(String header, List<Widget> children) {
    return Container(
      width: 400,
      child: Column(
        crossAxisAlignment: CrossAxisAlignment.start,
        children: [
          Text(
            header,
            style: TextStyle(color: Theme.of(context).accentColor, fontSize: 20),
          ),
          SizedBox(height: 20),
          _right(children),
          SizedBox(height: 40),
        ],
      ),
    );
  }

  List<Widget> buildDemoHeader() {
    return [
      TextButton(
        onPressed: () async => await launch('https://github.com/google/flutter.widgets/tree/master/packages/self_storing_input/example'),
        child: Text(
          'Source Code',
          style: TextStyle(
            color: Theme.of(context).accentColor,
            decoration: TextDecoration.underline,
          ),
        ),
      ),
    ];
  }

  List<Widget> buildDemoParameters() {
    return [
      CheckboxListTile(
        controlAffinity: ListTileControlAffinity.leading,
        title: Text('Fail the save operation'),
        value: _saver.failSaving,
        onChanged: (v) => setState(() => _saver.failSaving = v),
      ),
      SizedBox(height: 10),
      TextFormField(
        onChanged: (v) => setState(() => _saver.delay = Duration(milliseconds: int.parse(v))),
        initialValue: _saver.delay.inMilliseconds.toString(),
        keyboardType: TextInputType.number,
        decoration: InputDecoration(labelText: 'Delay time for the save operation, ms'),
        inputFormatters: [FilteringTextInputFormatter.digitsOnly],
      )
    ];
  }

  List<Widget> buildDemo() {
    return [
      Text('${Fields.phrase}:'),
      SelfStoringText(
        Fields.phrase,
        overlayController: _controller,
        saver: _saver,
      ),
      SizedBox(height: 20),
      Text('${Fields.paragraph}:'),
      SelfStoringText(
        Fields.paragraph,
        overlayController: _controller,
        saver: _saver,
        style: SelfStoringTextStyle(
          overlayStyle: OverlayStyle.forTextEditor(height: 130),
          keyboardType: TextInputType.multiline,
          maxLines: null,
        ),
      ),
      SizedBox(height: 20),
      Text('checkboxes:'),
      SelfStoringCheckbox(
        Fields.tristate,
        saver: _saver,
        overlayController: _controller,
        title: Text(Fields.tristate),
      ),
      SizedBox(height: 20),
      SelfStoringCheckbox(
        Fields.twostate,
        saver: _saver,
        overlayController: _controller,
        title: Text(Fields.twostate),
        tristate: false,
      ),
      SizedBox(height: 40),
      Text('${Fields.unselectableRadioGroup}:'),
      SelfStoringRadioGroup(
        Fields.unselectableRadioGroup,
        saver: _saver,
        isUnselectable: true,
        overlayController: _controller,
        items: {1: 'One', 2: 'Two', 3: 'Three'},
      ),
      SizedBox(height: 40),
      Text('${Fields.radioGroup}:'),
      SelfStoringRadioGroup(
        Fields.radioGroup,
        saver: _saver,
        overlayController: _controller,
        items: {1: 'One', 2: 'Two', 3: 'Three'},
      ),
    ];
  }

  List<Widget> buildStorageObserver() {
    return [
      for (var id in _saver.storage.keys) Text('$id: ${_saver.storage[id]}'),
    ];
  }
}

更多关于Flutter自动存储输入内容插件self_storing_input的使用的实战教程也可以访问 https://www.itying.com/category-92-b0.html

1 回复

更多关于Flutter自动存储输入内容插件self_storing_input的使用的实战系列教程也可以访问 https://www.itying.com/category-92-b0.html


self_storing_input 是一个用于 Flutter 的插件,它允许你自动存储用户在输入框中的内容。这样,即使用户关闭或刷新应用程序,他们之前的输入内容也会被保留,并且在下次打开应用程序时自动恢复。

安装插件

首先,你需要在 pubspec.yaml 文件中添加 self_storing_input 插件的依赖:

dependencies:
  flutter:
    sdk: flutter
  self_storing_input: ^0.1.0  # 请确保使用最新版本

然后,运行 flutter pub get 来获取依赖。

使用插件

  1. 导入插件

    在你的 Dart 文件中导入 self_storing_input 插件:

    import 'package:self_storing_input/self_storing_input.dart';
    
  2. 创建 SelfStoringInput 字段

    使用 SelfStoringInput 替代普通的 TextFieldTextFormField,并为其指定一个唯一的 storageKey。这个键用于在本地存储中唯一标识输入内容。

    SelfStoringInput(
      storageKey: 'username', // 唯一的存储键
      decoration: InputDecoration(labelText: '用户名'),
    ),
    

    你可以像使用普通的 TextField 一样使用 SelfStoringInput,并且它的值会在应用关闭后自动保存和恢复。

  3. 示例代码

    以下是一个完整的示例,展示了如何在 Flutter 应用中使用 self_storing_input

    import 'package:flutter/material.dart';
    import 'package:self_storing_input/self_storing_input.dart';
    
    void main() {
      runApp(MyApp());
    }
    
    class MyApp extends StatelessWidget {
      @override
      Widget build(BuildContext context) {
        return MaterialApp(
          title: 'Self Storing Input Demo',
          theme: ThemeData(
            primarySwatch: Colors.blue,
          ),
          home: SelfStoringInputDemo(),
        );
      }
    }
    
    class SelfStoringInputDemo extends StatelessWidget {
      @override
      Widget build(BuildContext context) {
        return Scaffold(
          appBar: AppBar(
            title: Text('Self Storing Input Demo'),
          ),
          body: Padding(
            padding: const EdgeInsets.all(16.0),
            child: Column(
              children: [
                SelfStoringInput(
                  storageKey: 'username',
                  decoration: InputDecoration(labelText: '用户名'),
                ),
                SizedBox(height: 20),
                SelfStoringInput(
                  storageKey: 'email',
                  decoration: InputDecoration(labelText: '电子邮件'),
                ),
              ],
            ),
          ),
        );
      }
    }
回到顶部