Unable to validate input using TextFormField and FlatButton - android-studio

I am currently working on a flutter application. I am trying to get the user input using TextFormField and passing it to the next page using the Navigator inside FlatButton. But for some reason, it is not working as I expect it to.
Here is the code:
TextFormField(
decoration: InputDecoration(
enabledBorder: OutlineInputBorder(
borderRadius: BorderRadius.all(Radius.circular(8)),
borderSide: BorderSide(color: Colors.grey[200])),
focusedBorder: OutlineInputBorder(
borderRadius: BorderRadius.all(Radius.circular(8)),
borderSide: BorderSide(color: Colors.grey[300])),
filled: true,
fillColor: Colors.grey[100],
errorBorder: InputBorder.none,
focusedErrorBorder: InputBorder.none,
errorStyle: Theme.of(context).textTheme.caption,
hintText: 'Phone Number',
),
keyboardType: TextInputType.phone,
controller: _phoneController,
maxLength: 10,
validator: (value) {
print(value);
return isPhoneValid(value)
? 'Continue'
: "Input : 98XXXXXXXX";
},
),
FlatButton(
child: Text('Enter'),
textColor: Colors.white,
disabledColor: Colors.grey,
padding: EdgeInsets.all(16),
onPressed: (isPhoneValid(_phoneController.text))
? () {
Navigator.push(context, MaterialPageRoute(builder,(context)=>HomeScreen));
}
: null,
color: Colors.blue,
),
and these are outside the build function.
final _phoneController = TextEditingController();
bool isPhoneValid(String value) {
print('Function');
print(value);
return value.trim().length == 10;
}
For some reason, the onPressed in the FlatButton is always mapped to null. Kindly guide me in this regard.
Thanks in advance.
PS: The validator inside TextFormField also does not seem to work.

It's not clear the reason why you're building the onPressed in that way, it's not going to work the way you expect. Change your onPressed method to this
onPressed: () {
if (isPhoneValid(_phoneController.text)) {
Navigator.push(context, MaterialPageRoute(builder,(context)=>HomeScreen));
}
}
EDIT
In order to disable button until text field is valid you have to listen for text changes
bool _canPressButton = false;
#override
void initState() {
_phoneController.addListener(_checkIfCanPressButton);
super.initState();
}
void _checkIfCanPressButton() {
var canPressButton = isPhoneValid(_phoneController.text);
if (canPressButton != _canPressButton) {
setState(() => _canPressButton = canPressButton);
}
}
Then you could do
onPressed: _canPressButton ?
? () => Navigator.push(context, MaterialPageRoute(builder: (context) => HomeScreen))
: null,

Related

Flutter: How do you get rid of a widget when you leave the screen or press back?

I'm creating a simple chatting app and I've added some authentication validation. During login or registration, when I get an error message from firebase, a widget pops up displaying the error. How do I make sure this widget goes away when I leave the screen? Right now if I press back it goes to the welcome screen and when I go back to the login screen, the error is still there. Here's the widget-
class ErrorMessage extends StatefulWidget {
#override
_ErrorMessageState createState() => _ErrorMessageState();
}
class _ErrorMessageState extends State<ErrorMessage> {
#override
Widget build(BuildContext context) {
if (error != null) {
return Container(
width: double.infinity,
color: Colors.amberAccent,
padding: EdgeInsets.all(8),
child: Row(
children: <Widget>[
Padding(
padding: EdgeInsets.only(right: 8),
child: Icon(Icons.error_outline),
),
Expanded(
child: Text(error, maxLines: 3),
),
Padding(
padding: EdgeInsets.only(left: 8),
child: IconButton(
icon: Icon(Icons.close),
onPressed: () {
setState(() {
error = null;
});
},
),
),
],
),
);
}
return SizedBox(
height: 0,
width: 0,
);
}
}
Instead of using a custom made widget just for displaying error/warning messages, I suggest using something like awesome_dialog which already has autoHide capability.
For example, this one will close itself after 4secs:
AwesomeDialog(
context: context,
animType: AnimType.LEFTSLIDE,
dismissOnTouchOutside: true,
dismissOnBackKeyPress: true,
headerAnimationLoop: true,
dialogType: DialogType.WARNING,
autoHide: Duration(seconds: 4),
body: Container(
child: Center(
child: Text(errorMessage, maxLines: 3),
),
)

How to create a simple google maps address search with autocomplete in flutter and get latitude and longitude?

I'm new at Flutter and I'm trying to build a simple google maps app. I've already implemented google maps to the app and it is running perfect.
But now I want to add google maps autocomplete and I can't find a simple tutorial or example that is focused on it.
I have a TextField and I want to show places and addresses below it according to what the user types.
After showing the results, I need to get its latitude and longitude to mark on the map. The code below represents my BottomSheet, that contains my TexField and need to implement some list below it after some written text.
void _settingModalBottomSheet(context) {
double statusBarHeight = MediaQuery.of(context).padding.top;
showModalBottomSheet(
context: context,
builder: (builder) {
return Container(
padding: EdgeInsets.only(top: statusBarHeight),
color: Colors.transparent,
child: Container(
height: MediaQuery.of(context).size.height,
decoration: BoxDecoration(
color: Colors.blueAccent,
borderRadius: BorderRadius.only(
topLeft: const Radius.circular(10.0), topRight: const Radius.circular(10.0))),
child: Column(
children: <Widget>[
Padding(
padding: const EdgeInsets.only(top: 8.0, left: 8.0, right: 8.0),
child: Container(
height: 50.0,
width: double.infinity,
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(10.0),
color: Colors.white
),
child: TextField(
textInputAction: TextInputAction.search,
decoration: InputDecoration(
hintText: "Para onde vamos?",
border: InputBorder.none,
contentPadding: EdgeInsets.only(left: 15.0, top: 15.0),
suffixIcon: IconButton(
icon: Icon(Icons.search),
onPressed: searchAndNavigate,
iconSize: 30.0,
)
),
onChanged: (val) {
setState(() {
searchAddr = val;
}
);
},
onSubmitted: (term) {
searchAndNavigate();
},
),
),
),
],
)
),
);
}
);
}
You can use flutter_google_places plugin which shows the places in the autocomplete list as you type it and also returns lat and long of the place/address selected.
===== Working code =======
Add flutter_google_places plugin and import it in your dart file.
Add geo_coder plugin and import it in same dart file. (Required to access geocoding services)
Generate google api key for your project.
main.dart:
void main() => runApp(MyApp());
const kGoogleApiKey = "Api_key";
GoogleMapsPlaces _places = GoogleMapsPlaces(apiKey: kGoogleApiKey);
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
body: demo(),
),
);
}
}
class demo extends StatefulWidget {
#override
demoState createState() => new demoState();
}
class demoState extends State<demo> {
#override
Widget build(BuildContext context) {
return Scaffold(
body: Container(
alignment: Alignment.center,
child: RaisedButton(
onPressed: () async {
// show input autocomplete with selected mode
// then get the Prediction selected
Prediction p = await PlacesAutocomplete.show(
context: context, apiKey: kGoogleApiKey);
displayPrediction(p);
},
child: Text('Find address'),
)
)
);
}
Future<Null> displayPrediction(Prediction p) async {
if (p != null) {
PlacesDetailsResponse detail =
await _places.getDetailsByPlaceId(p.placeId);
var placeId = p.placeId;
double lat = detail.result.geometry.location.lat;
double lng = detail.result.geometry.location.lng;
var address = await Geocoder.local.findAddressesFromQuery(p.description);
print(lat);
print(lng);
}
}
}
Result:
When you tap on Find Address button, it opens new screen with built-in search app bar in which you can type address / place you are looking for which shows corresponding results in autocomplete list and prints lat and long of the place you selected.
lat: 52.3679843
lng: 4.9035614

Dynamically update keyboardType in Flutter

I have a search TextFied and a Tabbar allowing to search by a number or a text.
When the TabBar is Fired/Tapped the keyboard type should be updated.
The listener allowing to detect the type is correctly fired
The build method is fired and the Textfield is rebuild with the keyboardType
But the keyboard type is not updated
_handleTabSelection() {
if (_tabController.indexIsChanging) {
switch (_tabController.index) {
case kNameIndex:
_searchBy = RunnersSubscriptionsSearchBy.name;
_keyboardType = TextInputType.text;
break;
case kTibibIndex:
_searchBy = RunnersSubscriptionsSearchBy.tibib;
_keyboardType = TextInputType.number;
//_focus.unfocus();
break;
}
setState(() {
;
});
}
}
And the Build searchBar with TextField
_buildSearchBar() {
return Container(
color: Theme.of(context).secondaryHeaderColor,
child: new Padding(
padding: const EdgeInsets.all(5),
child: new Card(
child: new ListTile(
contentPadding: EdgeInsets.only(left: 8, right: 0),
leading: new Icon(Icons.search),
title: new TextField(
keyboardType: _keyboardType,
focusNode: _focus,
controller: _searchTextFieldEditingController,
decoration: new InputDecoration(
hintText: _searchHintTextFromSearchType(_searchBy),
border: InputBorder.none),
),
trailing: new IconButton(
icon: new Icon(Icons.cancel),
onPressed: () {
_searchTextFieldEditingController.clear();
//onSearchTextChanged('');
},
),
),
),
),
);
}
You can use this:
FocusScope.of(context).requestFocus(_blankNode);
Future.delayed(Duration(seconds: 0)).then((v){
FocusScope.of(context).requestFocus(_nameNode);
});
Maybe help you.

Flutter dropdown text field

I am still new to Flutter. Is there an example of a material dropdown list text field? I saw the example on Material Text Field but I didn't find anywhere in the documentation on how to implement this. Thanks for your help on this.
UPDATED :
Text form field with a dropdown
var _currencies = [
"Food",
"Transport",
"Personal",
"Shopping",
"Medical",
"Rent",
"Movie",
"Salary"
];
FormField<String>(
builder: (FormFieldState<String> state) {
return InputDecorator(
decoration: InputDecoration(
labelStyle: textStyle,
errorStyle: TextStyle(color: Colors.redAccent, fontSize: 16.0),
hintText: 'Please select expense',
border: OutlineInputBorder(borderRadius: BorderRadius.circular(5.0))),
isEmpty: _currentSelectedValue == '',
child: DropdownButtonHideUnderline(
child: DropdownButton<String>(
value: _currentSelectedValue,
isDense: true,
onChanged: (String newValue) {
setState(() {
_currentSelectedValue = newValue;
state.didChange(newValue);
});
},
items: _currencies.map((String value) {
return DropdownMenuItem<String>(
value: value,
child: Text(value),
);
}).toList(),
),
),
);
},
)
Hope this helps!
You want the DropdownButton or DropdownButtonFormField
https://api.flutter.dev/flutter/material/DropdownButton-class.html
and the DropdownMenuItem
https://api.flutter.dev/flutter/material/DropdownMenuItem-class.html
return DropdownButtonFormField(
items: categories.map((String category) {
return new DropdownMenuItem(
value: category,
child: Row(
children: <Widget>[
Icon(Icons.star),
Text(category),
],
)
);
}).toList(),
onChanged: (newValue) {
// do other stuff with _category
setState(() => _category = newValue);
},
value: _category,
decoration: InputDecoration(
contentPadding: EdgeInsets.fromLTRB(10, 20, 10, 20),
filled: true,
fillColor: Colors.grey[200],
hintText: Localization.of(context).category,
errorText: errorSnapshot.data == 0 ? Localization.of(context).categoryEmpty : null),
);
Other answers have fully described what you need, but here is an example that puts it all together, this is a reusable dropdown textfield widget that allows you to specify a list of options of any type (without losing dart's beautiful type system).
class AppDropdownInput<T> extends StatelessWidget {
final String hintText;
final List<T> options;
final T value;
final String Function(T) getLabel;
final void Function(T) onChanged;
AppDropdownInput({
this.hintText = 'Please select an Option',
this.options = const [],
this.getLabel,
this.value,
this.onChanged,
});
#override
Widget build(BuildContext context) {
return FormField<T>(
builder: (FormFieldState<T> state) {
return InputDecorator(
decoration: InputDecoration(
contentPadding: EdgeInsets.symmetric(
horizontal: 20.0, vertical: 15.0),
labelText: hintText,
border:
OutlineInputBorder(borderRadius: BorderRadius.circular(5.0)),
),
isEmpty: value == null || value == '',
child: DropdownButtonHideUnderline(
child: DropdownButton<T>(
value: value,
isDense: true,
onChanged: onChanged,
items: options.map((T value) {
return DropdownMenuItem<T>(
value: value,
child: Text(getLabel(value)),
);
}).toList(),
),
),
);
},
);
}
}
And you may use it like this:
AppDropdownInput(
hintText: "Gender",
options: ["Male", "Female"],
value: gender,
onChanged: (String value) {
setState(() {
gender = value;
// state.didChange(newValue);
});
},
getLabel: (String value) => value,
)
Following Jeff Frazier's answer, You can have more customization by using DropdownButton2 or DropdownButtonFormField2 from DropdownButton2 package. It's based on Flutter's core DropdownButton with more options you can customize to your needs.
This answer provide a example using a DropdownButtonFormField a convenience widget that wraps a DropdownButton widget in a FormField.
Ideal if you are using a Material FormField
'Dropdown' may not be the correct word that you are using to describe the design of text field referred in your material design example.
Here is how to implement it in Flutter:
import 'package:flutter/material.dart';
void main() {
runApp(TextFieldExample());
}
class TextFieldExample extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Text Field Example',
home: HomePage(),
theme: ThemeData(
primaryColor: Colors.deepPurple,
accentColor: Colors.white,
),
);
}
}
class HomePage extends StatelessWidget {
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('Text Field Example'),
),
body: Padding(
padding: const EdgeInsets.all(16.0),
child: Column(
children: <Widget>[
//Material example
TextField(
decoration: InputDecoration(
filled: true,
hintText: 'Enter text',
labelText: 'Default text field'),
controller: new TextEditingController(),
),
SizedBox(
height: 16.0,
),
//Alternate
TextField(
decoration: InputDecoration(
border: OutlineInputBorder(),
hintText: 'Enter text',
labelText: 'Text field alternate'),
controller: new TextEditingController(),
),
],
),
),
);
}
}
This sample app contains two different examples of text field design that shrink and expand the associated label.
Gif of sample app - click here

How do you adjust the height and borderRadius of a BottomSheet in Flutter?

I'm probably missing something obvious here, but my BottomSheet only takes up the bottom half the screen, even though the widgets in it take up more space. So now there is scrolling behavior inside the BottomSheet. I'd like to be able to increase the BottomSheet so that the user doesn't have to scroll as much.
I also want to add a borderRadius to the top of my BottomSheet, so that it looks more "modal"-y or "tab"-like.
Code:
void _showBottomSheet(BuildContext context) {
showModalBottomSheet<Null>(
context: context,
builder: (BuildContext context) {
return _bottomSheetScreen; // defined earlier on
},
);
}
I've tried:
showModalBottomSheet<Null>(
context: context,
builder: (BuildContext context) {
return Container(
decoration: BoxDecoration(
borderRadius: _borderRadius,
),
height: 1000.0,
child: _bottomSheetScreen,
);
},
);
but it seems like that only affects the contents inside the BottomSheet, and does not customize the BottomSheet itself.
Default height for bottomSheet is half the screenSize
If you want your bottomSheet to EXPAND according to your content DYNAMICALLY
use below code
showModalBottomSheet<dynamic>(
isScrollControlled: true,
context: context,
builder: (BuildContext bc) {
return Wrap(
children: <Widget>[...]
)
}
)
This will automatically expand the bottomSheet according to content inside.
For adding a radius on top of bottomSheet return below code to `bottomSheet'
Container(
child: Container(
decoration: new BoxDecoration(
color: forDialog ? Color(0xFF737373) : Colors.white,
borderRadius: new BorderRadius.only(
topLeft: const Radius.circular(25.0),
topRight: const Radius.circular(25.0))),
child: yourWidget(),
),
)
Complete code meeting both requirements
showModalBottomSheet<dynamic>(
isScrollControlled: true,
context: context,
builder: (BuildContext bc) {
return Wrap(
children: <Widget>[
Container(
child: Container(
decoration: new BoxDecoration(
color: forDialog ? Color(0xFF737373) : Colors.white,
borderRadius: new BorderRadius.only(
topLeft: const Radius.circular(25.0),
topRight: const Radius.circular(25.0))),
child: yourWidget(),
),
)
]
)
}
)
It's possible this way
showModalBottomSheet(
context: context,
isScrollControlled: true,
backgroundColor: Colors.transparent,
builder: (context) => Container(
height: MediaQuery.of(context).size.height * 0.75,
decoration: new BoxDecoration(
color: Colors.white,
borderRadius: new BorderRadius.only(
topLeft: const Radius.circular(25.0),
topRight: const Radius.circular(25.0),
),
),
child: Center(
child: Text("Modal content goes here"),
),
),
);
Set isScrollControlled: true and backgroundColor: Colors.transparent for the modal
Provide a Container with required height: as root widget to modal builder
Provide BoxDecoration with required borderRadius for the Container
You can use a Column Inside a SingleChildScrollView to dynamically change the height of bottom sheet and also it gets scrollable once it exceeds the available max height, make sure the isScrollControlled is set to true,
And for the border radius the shape property will help you add the borderRadius to the bottomsheet.
here's a dartpad example for the same
Future<void> _showBottomSheet() async {
return showModalBottomSheet(
isScrollControlled: true,
shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(13)),
backgroundColor: Colors.white,
context: context,
builder: (context) => SingleChildScrollView(
child: Column(
crossAxisAlignment: CrossAxisAlignment.center,
children: List.generate(kBoxes, (index) => _squareBox(index)))),
);
}
No need to wrap anything. Only set:
isScrollControlled: true in showModalBottomSheet
shrinkWrap: true, in ListView
Here is the minimal general code:
import 'package:flutter/material.dart';
Future<Widget> show123(BuildContext context) {
return showModalBottomSheet<dynamic>(
useRootNavigator: true,
isScrollControlled: true,
context: context,
builder: (BuildContext bc) {
return ListView(
shrinkWrap: true,
children: [
ListItem(),
ListItem(),
ListItem(),
],
);
});
}
You can get inspired by my case which depends on the number of AlbumRow dynamically. If the height reaches the maximum, you can get to the bottom by scrolling.
import 'package:flutter/material.dart';
Future<Widget> showBottomSheet(BuildContext context) {
return showModalBottomSheet<dynamic>(
useRootNavigator: true,
barrierColor: Colors.black.withOpacity(0.5),
isScrollControlled: true,
context: context,
builder: (BuildContext bc) {
return ConstrainedBox(
constraints: BoxConstraints(maxHeight: MediaQuery.of(context).size.height * 0.9),
child: Container(
decoration: new BoxDecoration(
color: Colors.blue, borderRadius: new BorderRadius.only(topLeft: const Radius.circular(25.0), topRight: const Radius.circular(25.0))),
child: ListView(
shrinkWrap: true,
children: [
Padding(
padding: const EdgeInsets.fromLTRB(30, 30, 30, 45),
child: Text(
'Choose Album',
textAlign: TextAlign.center,
),
),
AlbumRow(title: 'For Weekends arta iretnairstnaisetn aistn aisetn'),
AlbumRow(title: 'Creative'),
AlbumRow(title: 'Christmas'),
AlbumRow(title: 'For Weekends arta iretnairstnaisetn aistn aisetn'),
],
),
),
);
});
}
Use the Code Below
Note : If You are using column then use mainAxisSize: MainAxisSize.min
// make isScrollControlled : true
// if using column then make - mainAxisSize: MainAxisSize.min
showModalBottomSheet<dynamic>(
isScrollControlled: true,
context: context,
builder: (BuildContext bc) {
return YourWidget();
}
)
For changing the height of bottomsheet it's better to use the bottomsheet's constraints and isScrollControlled properties.
Like this:
showModalBottomSheet(
constraints: BoxConstraints.loose(Size(
MediaQuery.of(context).size.width,
MediaQuery.of(context).size.height * 0.75)), // <= this is set to 3/4 of screen size.
isScrollControlled: true, // <= set to true. setting this without constrains may cause full screen bottomsheet.
context: context,
builder: (context) => yourWidget()
);
For border radius use the shape property:
showModalBottomSheet(
shape: const RoundedRectangleBorder(
borderRadius: BorderRadius.vertical(top: Radius.circular(45))), // <= set preferable radius.
context: context,
builder: (context) => yourWidget()
);
Use showBottomSheet instead of showModalBottomSheet
Create global key and a listener
final _scaffoldKey = new GlobalKey<ScaffoldState>();
VoidCallback _showPersBottomSheetCallBack;
Write your method to show the sheet
void _showBottomSheet() {
setState(() {
_showPersBottomSheetCallBack = null;
});
_scaffoldKey.currentState
.showBottomSheet((context) {
return new Container(
height: MediaQuery.of(context).size.height-100.0,
color: Colors.greenAccent,
child: new Center(
child: new Text("Hi BottomSheet"),
),
);
})
.closed
.whenComplete(() {
if (mounted) {
setState(() {
_showPersBottomSheetCallBack = _showBottomSheet;
});
}
});
}
initialize the listener
void initState() {
super.initState();
_showPersBottomSheetCallBack = _showBottomSheet;
}
Call the method wherever you required
new RaisedButton(
onPressed: _showPersBottomSheetCallBack,
child: new Text("Persistent"),
),
Hope it helps !
Lately I found an workaround for this. By setting the canvasColor property to Colors.transparent in your app's theme, we can make the BottomSheet's overlay disappear.
return new MaterialApp(
title: 'MyApp',
theme: new ThemeData(
primarySwatch: Colors.blue,
canvasColor: Colors.transparent,
),
//...
);
Once you set this up, you may use ClipRRect or Decoration with rounded corners.
here is the simplest code working in 2021
showModalBottomSheet(
context: context,
isScrollControlled: true, // <-- make bottom sheet resize to content height
shape: RoundedRectangleBorder( // <-- for border radius
borderRadius: BorderRadius.only(
topLeft: Radius.circular(15.0),
topRight: Radius.circular(15.0),
),
),
builder: (BuildContext context) {
return Container() // <-- any widget you want
});
In the above code by #Shyju Madathil you need to add key in scaffold to make it work
return new Scaffold(
key: _scaffoldKey,
....
Based on Vicky's answer, Wrap could make alignments miserable. Use instead Column(mainAxisSize: MainAxisSize.min, children: [...]) in the widget. Implementing that in your example should look like:
void _showBottomSheet(BuildContext context) {
showModalBottomSheet<Null>(
context: context,
builder: (BuildContext context) {
return Column(
mainAxisAxisSize: MainAxisSize.min,
children: [
_bottomSheetScreen
]); // defined earlier on
},
);
}
If you want to control the scrolls with swipes, then try setting isScrollControlled: true on the showModalBottomSheet().
You can adjust the height by setting the height of your main container either by a constant ex : 800 or by using MediaQuery ex :
if i want to show only 2 /3 of the screen
MediaQuery.of(context).size.height -
(MediaQuery.of(context).size.height / 3)
for the radius first you have to set the
showModalBottomSheet(
backgroundColor: Colors.transparent,
and then you container color to White or any color you wanted , example :
return Container(
decoration: BoxDecoration(
color: Colors.white,
borderRadius: BorderRadius.only(
topLeft: const Radius.circular(16),
topRight: const Radius.circular(16))),
child:
You can adjust the height by setting isScrollControlled: true and wrapping the BottomSheet inside FractionallySizedBox. It would look something like this:
showModalBottomSheet<void>(
context: context,
//This
isScrollControlled: true,
builder: (BuildContext context) {
return StatefulBuilder(
builder: (BuildContext context, StateSetter state) {
return FractionallySizedBox(
//Here specify the high of the BottomSheet
heightFactor: 0.9,
child:BottomSheet(
.
.
.
.
.
.
));
});
});
Simple way to do this:
showModalBottomSheet(
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.only(
topRight: Radius.circular(15),
topLeft: Radius.circular(15),
),
),
context: context,
builder: (context) {
return Wrap(
children: [
Container(
height: 40,
child: Center(
child: Text(
"Edit Profile",
style: TextStyle(
fontWeight: FontWeight.bold,
),
),`
),
),
],
);
});
In my case, setting the 'isScrollable' parameter to "true" makes the bottomsheet go past halfway through the screen.
This is my solution.It can adjust height and has a max height.If the content over max height.It can be scrolled
showModalBottomSheet<void>(
context: context,
isScrollControlled: true,
backgroundColor: Colors.white,
// elevation: 10,
shape: const RoundedRectangleBorder(
borderRadius: BorderRadius.only(
topLeft: Radius.circular(12),
topRight: Radius.circular(12),
)),
builder: (context) {
return ConstrainedBox(
constraints: const BoxConstraints(maxHeight: 300),
child: SingleChildScrollView(
scrollDirection: Axis.vertical,
child: Column(
children: List.generate(20, (index) => Text("data$index")),
)),
);
},
);

Resources