Old iron remember to forward, Brother Cat will present more Flutter good articles ~~~~
Wechat Flutter research group Ducafecat
The original
Evandrmb.medium.com/flutter-mod…
code
Github.com/evandrmb/bo…
reference
- Material. IO/components /…
The body of the
According to the material design guide, the bottom table is a small tool for displaying additional content anchored at the bottom of the screen. While it would be nice to know the design rules for using this, that is not the goal of this article. For more detailed information on the principles of floor Design, see “Sheets: Bottom — Material Design”.
Now that you know BottomSheet, you might ask yourself: what is a ModalBottomSheet? How do we use them in Flutter?
Ok, first question, there are two types of underlying tables: modal and persistent. Persistence remains visible when the user interacts with the screen. Google Maps is one example.
On the other hand, stereotyped actions prevent users from doing other things in the application. You can use them to confirm certain actions, or to request additional data, such as asking the user how much interchange is required when ordering in an e-commerce application, and so on.
In this article, we’ll show how to use it by creating a simple weight tracking application where we can submit our weight and view our previous weight. Instead of entering the details of the application, we go directly to the ModalBottomSheet implementation.
To display it, you need to call showModalBottomSheet from the context with the Scaffold, otherwise you will get an error. In other words, let’s start building our table.
The first thing to know is that ModalBottomSheets defaults to half the height of the screen. In order to change this, you must pass true to the isScrollControlled parameter and return a widget that matches the size we expect, so let’s do that.
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: [ ], ), ); }); }Copy the code
Now, we need to add something so that our users can enter their weights let’s add a TextInput and give it a TextEditingController (this way its value remains even if our worksheet is accidentally closed and the user opens it again).
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, ), ), ), ], ), ); }); }Copy the code
It looks good, but now we have a problem. When the user clicks our TextField keyboard on it, why? Our worksheet doesn’t adjust its position when the keyboard is on, and we can make the worksheet bigger, but that doesn’t solve our problem because we still need to add a field where the user can enter the date they recorded the weight. So what’s the solution? This is simple, if we open the keyboard and let our worksheet on top of it, we can implement this, giving our container an edge margin. In viewinset.bottom, we get the following result:
It looks nice at first, but don’t you think it would be smoother if we added some radii to the paper? Let’s do this by adding shapeProperty as shown below.
showModalBottomSheet(
isScrollControlled: true,
context: context,
shape: const RoundedRectangleBorder(
borderRadius: BorderRadius.only(
topLeft: Radius.circular(8),
topRight: Radius.circular(8))),Copy the code
Cool, now let’s make our gadget to choose a date. Normally, you would create a widget to handle this logic and expose the selected values using the ValueChanged function, but to illustrate the problems you might face in the future, let’s create all the logic inside the worksheet itself.
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), ], ), ), ), ], ), ) ], ), ); }); }Copy the code
Note that I have added selectedDatevariable to our home page, which you can see in the repository link I provided at the end. But now we have a problem, even though we are using setStateOutlineButton to update the value of selectedDate, the old value is still displayed before reopening the worksheet, as shown below.
To solve this problem, we need to pass the OutlinedButton to the StatefulBuilder (or you can create a new widget and expose the changes using callbacks, as I said earlier, which is the right way, by the way).
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'(() [[() [() [() [() }); }Copy the code
This is the final version of our ModalBottomSheet!
Github.com/evandrmb/bo…
The elder brother of the © cat
ducafecat.tech/
github.com/ducafecat
The issue of
Open source
GetX Quick Start
Github.com/ducafecat/g…
News client
Github.com/ducafecat/f…
Strapi manual translation
getstrapi.cn
Wechat discussion group Ducafecat
A series of collections
The translation
Ducafecat. Tech/categories /…
The open source project
Ducafecat. Tech/categories /…
Dart programming language basics
Space.bilibili.com/404904528/c…
Start Flutter with zero basics
Space.bilibili.com/404904528/c…
Flutter combat news client from scratch
Space.bilibili.com/404904528/c…
Flutter component development
Space.bilibili.com/404904528/c…
Flutter Bloc
Space.bilibili.com/404904528/c…
Flutter Getx4
Space.bilibili.com/404904528/c…
Docker Yapi
Space.bilibili.com/404904528/c…