老铁记得 转发 ,猫哥会出现更多 Flutter 好文~~~~

微信 flutter 研修群 ducafecat

原文

https://evandrmb.medium.com/f...

代码

https://github.com/evandrmb/b...

参考

  • https://material.io/component...

注释

依据材质设计指南,底部表是一个小工具,用于显示锚定在屏幕底部的附加内容。尽管理解应用这个的设计规定很好,但这不是本文的指标。要理解更多对于底板设计准则的详细信息,请参阅“Sheets: bottom — Material Design”。

当初你晓得了 BottomSheet,你可能会问本人: 什么是 ModalBottomSheet?咱们如何应用他们在 Flutter?

好的,第一个问题,有两种底层表: 模态的和长久的。当用户与屏幕交互时,长久化放弃可见。谷歌地图利用就是一个例子。

另一方面,模式化的操作会阻止用户在应用程序中做其余动作。您能够应用它们来确认某些操作,或者申请额定的数据,比方询问用户在电子商务应用程序中订购时须要多少替换,等等。

在本文中,咱们将通过创立一个简略的体重跟踪应用程序来展现如何应用它,在这个应用程序中咱们能够提交咱们的体重并查看咱们之前的体重。咱们不会输出应用程序的详细信息,而是间接进入 ModalBottomSheet 实现。

要显示它,您须要从具备 Scaffold 的上下文调用 showModalBottomSheet,否则,您将失去一个谬误。也就是说,让咱们开始构建咱们的表格。

首先要晓得的是 ModalBottomSheets 的高度默认为屏幕的一半,为了扭转它,必须传递 true 给 isScrollControlled 参数,并返回一个与咱们冀望的大小相匹配的小部件,所以让咱们这样做。

void addWeight() {    showModalBottomSheet(      isScrollControlled: true,      context: context,      builder: (context) {        var date = DateTime.now();            return Container(          height: 302,          padding: const EdgeInsets.all(16.0),          child: Column(            crossAxisAlignment: CrossAxisAlignment.start,            children: [            ],          ),        );      },    );  }

当初,咱们须要增加一些货色,以便咱们的用户能够输出他们的权重让咱们增加一个 TextInput 并给它一个 TextEditingController (这种形式即便咱们的工作表意外敞开时,用户再次关上它,它的值依然存在)。

void addWeight() {    showModalBottomSheet(      isScrollControlled: true,      context: context,      builder: (context) {        var date = DateTime.now();            return Container(          height: 302,          padding: const EdgeInsets.all(16.0),          child: Column(            crossAxisAlignment: CrossAxisAlignment.start,            children: [                      padding: EdgeInsets.only(bottom: 24.0),                child: Text(                  'Register Weight',                  style: Styles.titleStyle,                ),              ),              TextField(                controller: weightInputController,                keyboardType: TextInputType.number,                decoration: InputDecoration(                  labelText: 'Weight (KG)',                  border: OutlineInputBorder(                    borderRadius: Styles.borderRadius,                  ),                ),              ),            ],          ),        );      },    );  }

看起来不错,但当初咱们有麻烦了。当用户点击咱们的 TextField 键盘在它下面,为什么?当键盘关上时,咱们的工作表不会调整地位,咱们能够把工作表做得更大,但这不能解决咱们的问题,因为咱们依然须要增加一个字段,用户能够在其中输出他们记录分量的日期。那么解决方案是什么呢?这很简略,如果关上键盘,咱们让咱们的工作表在它下面,咱们能够实现这一点,给咱们的容器一个边距的边缘。在 viewinset.bottom 中,咱们将失去以下后果:

它开始看起来很漂亮,然而你不认为如果咱们在纸上加一些半径会更平滑吗?让咱们通过增加如下所示的 shapeproperty 来实现。

showModalBottomSheet(      isScrollControlled: true,      context: context,      shape: const RoundedRectangleBorder(          borderRadius: BorderRadius.only(            topLeft: Radius.circular(8),            topRight: Radius.circular(8),          )),

酷,当初让咱们做咱们的小工具来抉择一个日期。通常,您会创立一个小部件来解决这个逻辑,并应用 ValueChanged 函数公开选定的值,然而为了阐明您未来可能面临的问题,让咱们在工作表自身外部创立所有逻辑。

void addWeight() {    showModalBottomSheet(      isScrollControlled: true,      context: context,      shape: const RoundedRectangleBorder(          borderRadius: BorderRadius.only(        topLeft: Radius.circular(8),        topRight: Radius.circular(8),      )),      builder: (context) {        return Container(          height: 360,          width: MediaQuery.of(context).size.width,          margin:              EdgeInsets.only(bottom: MediaQuery.of(context).viewInsets.bottom),          padding: const EdgeInsets.all(16.0),          decoration: BoxDecoration(            borderRadius: BorderRadius.circular(20),          ),          child: Column(            crossAxisAlignment: CrossAxisAlignment.start,            children: [              const Padding(                padding: EdgeInsets.only(bottom: 24.0),                child: Text(                  'Register Weight',                  style: Styles.titleStyle,                ),              ),              TextField(                controller: weightInputController,                keyboardType: TextInputType.number,                decoration: InputDecoration(                  labelText: 'Weight (KG)',                  border: OutlineInputBorder(                    borderRadius: Styles.borderRadius,                  ),                ),              ),              Padding(                padding: const EdgeInsets.symmetric(vertical: 8.0),                child: Row(                  children: [                    Expanded(                      child: Text(                        'Select a date',                        style: TextStyle(                          fontSize: 14,                          fontWeight: FontWeight.w500,                        ),                      ),                    ),                    Container(                      padding: const EdgeInsets.symmetric(horizontal: 4),                      margin: const EdgeInsets.symmetric(vertical: 8.0),                      height: 36,                      decoration: BoxDecoration(                        borderRadius: Styles.borderRadius,                      ),                      child: OutlinedButton(                        onPressed: () async {                          final now = DateTime.now();                          final result = await showDatePicker(                              context: context,                              initialDate: now,                              firstDate: now.subtract(                                const Duration(                                  days: 90,                                ),                              ),                              lastDate: now);                          if (result != null) {                            setState(() {                              selectedDate = result;                            });                          }                        },                        child: Row(                          mainAxisAlignment: MainAxisAlignment.spaceBetween,                          children: [                            Padding(                              padding: const EdgeInsets.only(right: 16.0),                              child:                                  Text('${formatDateToString(selectedDate)}'),                            ),                            Icon(Icons.calendar_today_outlined),                          ],                        ),                      ),                    ),                  ],                ),              )            ],          ),        );      },    );  }

须要留神的是,我曾经在咱们的主页中增加了 selectedDatevariable,你能够在我最初提供的存储库链接中看到这一点。然而当初咱们遇到了一个问题,只管咱们正在应用 setstateoutlinebutton 更新 selectedDate 的值,然而在从新关上工作表之前,依然会显示旧的值,如下所示。

为了解决这个问题,咱们须要将 OutlinedButton 传递给 StatefulBuilder (或者您能够创立一个新的小部件并应用回调公开更改,正如我后面所说的,顺便说一下,这是更正确的办法)。

void addWeight() {    showModalBottomSheet(      isScrollControlled: true,      context: context,      shape: const RoundedRectangleBorder(          borderRadius: BorderRadius.only(        topLeft: Radius.circular(8),        topRight: Radius.circular(8),      )),      builder: (context) {        return Container(          height: 360,          width: MediaQuery.of(context).size.width,          margin:              EdgeInsets.only(bottom: MediaQuery.of(context).viewInsets.bottom),          padding: const EdgeInsets.all(16.0),          decoration: BoxDecoration(            borderRadius: BorderRadius.circular(20),          ),          child: Column(            crossAxisAlignment: CrossAxisAlignment.start,            children: [              const Padding(                padding: EdgeInsets.only(bottom: 24.0),                child: Text(                  'Register Weight',                  style: Styles.titleStyle,                ),              ),              TextField(                controller: weightInputController,                keyboardType: TextInputType.number,                decoration: InputDecoration(                  labelText: 'Weight (KG)',                  border: OutlineInputBorder(                    borderRadius: Styles.borderRadius,                  ),                ),              ),              Padding(                padding: const EdgeInsets.symmetric(vertical: 8.0),                child: Row(                  children: [                    Expanded(                      child: Text(                        'Select a date',                        style: TextStyle(                          fontSize: 14,                          fontWeight: FontWeight.w500,                        ),                      ),                    ),                    Container(                        padding: const EdgeInsets.symmetric(horizontal: 4),                        margin: const EdgeInsets.symmetric(vertical: 8.0),                        height: 36,                        decoration: BoxDecoration(                          borderRadius: Styles.borderRadius,                        ),                        child: StatefulBuilder(                          builder: (context, setState) {                            return OutlinedButton(                              onPressed: () async {                                final now = DateTime.now();                                final result = await showDatePicker(                                    context: context,                                    initialDate: now,                                    firstDate: now.subtract(                                      const Duration(                                        days: 90,                                      ),                                    ),                                    lastDate: now);                                if (result != null) {                                  setState(() {                                    selectedDate = result;                                  });                                }                              },                              child: Row(                                mainAxisAlignment:                                    MainAxisAlignment.spaceBetween,                                children: [                                  Padding(                                    padding: const EdgeInsets.only(right: 16.0),                                    child: Text(                                        '${formatDateToString(selectedDate)}'),                                  ),                                  Icon(Icons.calendar_today_outlined),                                ],                              ),                            );                          },                        )),                  ],                ),              ),              Expanded(child: Container()),              ButtonBar(                children: [                  ElevatedButton(                    onPressed: () => Navigator.pop(context),                    child: Text('Cancel',                        style: TextStyle(                          color: Theme.of(context).primaryColor,                        )),                    style: ElevatedButton.styleFrom(                      primary: Colors.white,                      // minimumSize: Size(96, 48),                    ),                  ),                  ElevatedButton(                      onPressed: () {                        setState(() {                          weights.insert(                              0,                              WeightModel(                                value: double.parse(weightInputController.text),                                date: selectedDate,                              ));                        });                        Navigator.pop(context);                      },                      child: const Text('Register')),                ],              ),            ],          ),        );      },    );  }

这是咱们的 ModalBottomSheet 的最终版本!

https://github.com/evandrmb/b...


© 猫哥

https://ducafecat.tech/

https://github.com/ducafecat

往期

开源

GetX Quick Start

https://github.com/ducafecat/...

新闻客户端

https://github.com/ducafecat/...

strapi 手册译文

https://getstrapi.cn

微信探讨群 ducafecat

系列汇合

译文

https://ducafecat.tech/catego...

开源我的项目

https://ducafecat.tech/catego...

Dart 编程语言根底

https://space.bilibili.com/40...

Flutter 零根底入门

https://space.bilibili.com/40...

Flutter 实战从零开始 新闻客户端

https://space.bilibili.com/40...

Flutter 组件开发

https://space.bilibili.com/40...

Flutter Bloc

https://space.bilibili.com/40...

Flutter Getx4

https://space.bilibili.com/40...

Docker Yapi

https://space.bilibili.com/40...