持久底部 sheet 表单数据

Persistent bottom sheet form data

我在底部有一张表格sheet。单击一个按钮即可打开它。当用户在窗体外单击时,它可以关闭。如果用户重新打开表单,我想维护表单数据。我不想明确分配每个表单字段值。有没有其他方法可以保存表单状态并在再次创建底部 sheet 时重复使用它?

  void _modalBottomSheetMenu(BuildContext context, Widget form) async {
    await showModalBottomSheet<dynamic>(
        isDismissible: false,
        isScrollControlled:true,
        context: context,
        shape: RoundedRectangleBorder(
          borderRadius: BorderRadius.only(topLeft: Radius.circular(20), topRight: Radius.circular(20)),
        ),
        backgroundColor: Colors.white,
        builder: (BuildContext bc) {
          return SingleChildScrollView(
              child: Container(
                  padding:
                  EdgeInsets.only(bottom: MediaQuery.of(context).viewInsets.bottom),
                  child: Padding(
                      padding: const EdgeInsets.fromLTRB(20.0, 20.0, 20.0, 0.0),
                      child: form) // From with TextField inside
              ));}
    );

所以我终于找到了使用 Provider 维护状态的最佳方法之一。我还探索了其他方式,例如 BLOC,但它非常冗长。我们可以在其他情况下使用 BLOC,但 Provider 是底部情况下更好的解决方案 sheet.

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

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

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Bottom Sheet',
      theme: ThemeData(
        primarySwatch: Colors.blue,
      ),
      home: ChangeNotifierProvider(
        create: (context) => TitleDataNotifier(),
        child: ButtomSheetScreen(),
      ),
    );
  }
}

class TitleDataNotifier with ChangeNotifier {
  String _name;

  String get name => _name;

  set name(String name) {
    _name = name;
    notifyListeners();
  }
}

class AddTaskScreen extends StatefulWidget {
  final TitleDataNotifier valueProvider;

  AddTaskScreen(this.valueProvider);

  @override
  _AddTaskScreenState createState() => _AddTaskScreenState();
}

class _AddTaskScreenState extends State<AddTaskScreen> {
  final _controller = TextEditingController();

  @override
  void initState() {
    super.initState();
    _controller.text = widget.valueProvider.name;
  }

  void dispose() {
    _controller.dispose();
    super.dispose();
  }

  @override
  void deactivate() {
    widget.valueProvider.name = _controller.text;
    super.deactivate();
  }

  @override
  Widget build(BuildContext context) {
    return Container(
      padding: EdgeInsets.all(20.0),
      decoration: BoxDecoration(
        color: Colors.white,
        borderRadius: BorderRadius.only(
          topLeft: Radius.circular(20.0),
          topRight: Radius.circular(20.0),
        ),
      ),
      child: Column(
        crossAxisAlignment: CrossAxisAlignment.stretch,
        children: <Widget>[
          Text(
            'Add Task',
            textAlign: TextAlign.center,
            style: TextStyle(
                fontSize: 30.0,
                color: Colors.lightBlueAccent,
                fontWeight: FontWeight.w700),
          ),
          TextField(
            controller: _controller,
            autofocus: false,
            textAlign: TextAlign.center,
            onChanged: (newText) {
              widget.valueProvider._name = newText;
            },
          ),
          FlatButton(
            child: Text(
              'Add',
              style: TextStyle(color: Colors.white),
            ),
            color: Colors.lightBlueAccent,
            onPressed: () {
              Navigator.pop(context);
            },
          )
        ],
      ),
    );
  }
}

class ButtomSheetScreen extends StatelessWidget {
  void openBottomSheet(context) {
    var valueProvider = Provider.of<TitleDataNotifier>(context, listen: false);
    showModalBottomSheet<dynamic>(
      context: context,
      builder: (BuildContext context) {
        return ChangeNotifierProvider.value(
          value: valueProvider,
          child: StatefulBuilder(
              builder: (BuildContext context, StateSetter state) {
            return Padding(
              padding: EdgeInsets.only(
                  bottom: MediaQuery.of(context).viewInsets.bottom),
              child: Wrap(
                children: <Widget>[
                  AddTaskScreen(valueProvider),
                ],
              ),
            );
          }),
        );
      },
    );
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
        appBar: AppBar(
          title: Text(
            "Bottom Sheet",
          ),
        ),
        body: Center(
          child: Container(
              child: IconButton(
            icon: const Icon(Icons.work),
            onPressed: () {
              openBottomSheet(context);
            },
          )),
        ));
  }
}