Issue with provider when navigating between screens - flutter

I'm trying to learn more about provider but I'm facing an issue with an app I'm developing, specifically when I navigate to a screen. When I press on the button to take me to the history_screen is when I get an error from Provider, all the providers are declared at the top of the tree so not really sure why there's still an error.
Hopefully someone can help me!
See my code below and the error I get:
Main.dart
void main() {
runApp(
MyApp());
}
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MultiProvider(
providers: [
StreamProvider<List<Meds>>.value(
value: MedicinesNotifier().medicinesStream(),
initialData: MedicinesNotifier().meds,
updateShouldNotify: (_, __) => true),
//ChangeNotifierProvider<MedicinesNotifier>(create: (_) => MedicinesNotifier()),
ProxyProvider<List<Meds>,MedicinesNotifier>(
update:
(BuildContext context, List<Meds> meds1, MedicinesNotifier? medNoti) => MedicinesNotifier.med(meds1)
),
ChangeNotifierProvider<SearchHistoryData>(create: (_) => SearchHistoryData()),
],
child: MaterialApp(
title: 'Flutter Demo',
/*theme: ThemeData(
primarySwatch: Colors.blueGrey,
),*/
home: MyHomePage(),
),
);
}
}
home_page.dart
class _MyHomePageState extends State<MyHomePage> {
List<Meds> medFiltered = [];
TextEditingController searchController = new TextEditingController();
String searchText = "";
#override
Widget build(BuildContext context) {
bool isSearching = searchController.text.isNotEmpty;
return Scaffold(
bottomNavigationBar: BottomBar(),
body: SafeArea(
child: Container(
padding: EdgeInsets.all(20.0),
child: Column(
children: <Widget>[
Container(
child: TextField(
controller: searchController,
decoration: InputDecoration(
labelText: "Search",
border: new OutlineInputBorder(
borderSide: new BorderSide(
color: Theme.of(context).primaryColor,
),
borderRadius: BorderRadius.circular(30.0),
),
prefixIcon: Icon(Icons.search),
),
onChanged: (value) {
Provider.of<MedicinesNotifier>(context, listen: false)
.changeSearchString(value);
},
),
),
Expanded(
child:
ListView.builder(
shrinkWrap: true,
itemCount: isSearching == true
? context
.watch<MedicinesNotifier>()
.meds
.length
: context
.watch<List<Meds>>()
.length,
itemBuilder: (context, index) {
Meds med = isSearching == true
? context
.watch<MedicinesNotifier>()
.meds
[index]
: context
.watch<List<Meds>>()[index]; //medsStreamed[index];
return ListTile(
onTap: () {
context.read<MedicinesNotifier>().addHistory(med);
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => ChatScreen(
med: context.watch<MedicinesNotifier>().findMedicine(med),
)));
},
title: Text(med.name),
subtitle: Text(med.description.substring(0, 10)),
);
},
),
),
],
),
),
),
);
}
}
BottomBar widget
class BottomBar extends StatelessWidget {
#override
Widget build(BuildContext context) {
return BottomAppBar(
shape: CircularNotchedRectangle(),
color: Theme.of(context).primaryColor,
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: <Widget>[
IconButton(
icon: Icon(Icons.search),
color: Colors.white,
iconSize: 40.0,
onPressed: () {
Navigator.of(context).push(
MaterialPageRoute(builder: (context) => MyHomePage()));
},
),
IconButton(
color: Colors.white,
icon: Icon(Icons.history_edu),
iconSize: 40.0,
onPressed: () {
Navigator.of(context).push(
MaterialPageRoute(builder: (context) => HistoryScreen()));
},**//Causing the issue**
),
]),
);
}
}
history_screen.dart
class HistoryScreen extends StatefulWidget {
const HistoryScreen({Key? key}) : super(key: key);
#override
_HistoryScreenState createState() => _HistoryScreenState();
}
class _HistoryScreenState extends State<HistoryScreen> {
#override
Widget build(BuildContext context) {
//List<Meds> temp1 = context.watch<MedicinesNotifier>().history;
return Scaffold(
bottomNavigationBar: BottomBar(),
body: SafeArea(
child: Column(
children: <Widget>[
Container(
color: Theme.of(context).primaryColor,
child: Padding(
padding: EdgeInsets.fromLTRB(15.0, 0.0, 15.0, 30.0),
child: Row(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Column(
mainAxisAlignment: MainAxisAlignment.end,
children: <Widget>[
TextButton(
onPressed: () {},
child: Text(
"Filter",
style: TextStyle(
color: Colors.white,
),
),
),
],
),
],
),
),
),
Expanded(
child: Container(
//color: Colors.white54,
decoration: BoxDecoration(
color: Colors.white30,
borderRadius: BorderRadius.only(
topLeft: Radius.circular(30.0),
topRight: Radius.circular(30.0),
),
),
child: ClipRRect(
borderRadius: BorderRadius.only(
topLeft: Radius.circular(30.0),
topRight: Radius.circular(30.0),
),
child: Consumer<SearchHistoryData?>(**//Using Consumer here**
builder: (context, searchHistoryData, child) {
//assert(child != null);
return ListView.builder(
itemCount: searchHistoryData!.sizeOfHistory(),
itemBuilder: (BuildContext context, int index) {
//final historyData =
return Container(
margin: EdgeInsets.only(...
Exception caught
The following ProviderNotFoundException was thrown building Consumer<SearchHistoryData?>(dirty):
Error: Could not find the correct Provider<SearchHistoryData?> above this Consumer<SearchHistoryData?> Widget
This happens because you used a BuildContext that does not include the provider
of your choice. There are a few common scenarios:
You added a new provider in your main.dart and performed a hot-reload.
To fix, perform a hot-restart.
The provider you are trying to read is in a different route.
Providers are "scoped". So if you insert of provider inside a route, then
other routes will not be able to access that provider.
You used a BuildContext that is an ancestor of the provider you are trying to read.
Make sure that Consumer<SearchHistoryData?> is under your MultiProvider/Provider<SearchHistoryData?>.
This usually happens when you are creating a provider and trying to read it immediately.
For example, instead of:
Widget build(BuildContext context) {
return Provider<Example>(
create: (_) => Example(),
// Will throw a ProviderNotFoundError, because `context` is associated
// to the widget that is the parent of `Provider<Example>`
child: Text(context.watch<Example>()),
),
}
consider using builder like so:
Widget build(BuildContext context) {
return Provider<Example>(
create: (_) => Example(),
// we use `builder` to obtain a new `BuildContext` that has access to the provider
builder: (context) {
// No longer throws
return Text(context.watch<Example>()),
}
),
}

Related

showModalBottomSheet rounded corner

I am facing strange issue in showModalBottomSheet. Rounded corner is not working. Please see the code. But ff I add the Text('Title') before Expanded widget, it is showing rounded corner.
But I can't add the title here because DownloadedDharmaSongScreen has AppBar.
showModalBottomSheet(
context: context,
isScrollControlled: true,
shape: const RoundedRectangleBorder(
borderRadius: BorderRadius.only(
topLeft: Radius.circular(_radius),
topRight: Radius.circular(_radius),
),
),
builder: (BuildContext context) {
return DraggableScrollableSheet(
initialChildSize: 0.9,
expand: false,
builder: (context, scrollController) {
return Column(
mainAxisSize: MainAxisSize.min,
children: [
Expanded(
child: DownloadedDharmaSongScreen(
controller: scrollController,
destinationFavourite: widget.destinationFavourite,
sourceFavourite: favourite,
socialMode: widget.socialMode,
),
),
const SizedBox(
height: 60,
)
],
);
},
);
},
);
DownloadedDharmaSongScreen
class DownloadedDharmaSongScreen extends StatefulWidget {
static const routeName = '/downloaded_dharma_song';
final ScrollController? controller;
final Favourite? destinationFavourite;
final Favourite? sourceFavourite;
final SocialMode socialMode;
const DownloadedDharmaSongScreen({
Key? key,
this.controller,
this.destinationFavourite,
this.sourceFavourite,
required this.socialMode,
}) : super(key: key);
#override
State<DownloadedDharmaSongScreen> createState() =>
_DownloadedDharmaSongScreen();
}
class _DownloadedDharmaSongScreen extends
State<DownloadedDharmaSongScreen> {
List<FavouriteSong> favouriteSongs = [];
List<FavouriteSong> selectedFavouriteSongs = [];
bool isSelected = false;
_loadDownloadFiles() async {
BlocProvider.of<FavouriteSongBloc>(context).add(
GetAllDownloadedSongsByFavouriteId(
favouriteId: widget.sourceFavourite!.id!));
}
#override
void initState() {
super.initState();
_loadDownloadFiles();
}
#override
Widget build(BuildContext context) {
return Scaffold(
backgroundColor: Theme.of(context).scaffoldBackgroundColor,
appBar: AppBar(
centerTitle: true,
backgroundColor: Theme.of(context).backgroundColor,
elevation: 0,
title: AutoSizeText(
widget.sourceFavourite!.name,
style: Theme.of(context).appBarTheme.titleTextStyle,
),
leading: IconButton(
onPressed: () {
Navigator.pop(context);
},
icon: Icon(
Icons.arrow_back,
color: Theme.of(context).primaryIconTheme.color!,
),
),
actions: [
Container(
padding: const EdgeInsets.only(left: 10, right: 10),
child: Row(
mainAxisSize: MainAxisSize.min,
children: [
CupertinoButton(
minSize: double.minPositive,
padding: const EdgeInsets.only(right: 5),
child: Icon(Icons.done,
color: selectedFavouriteSongs.isNotEmpty
? Theme.of(context).primaryIconTheme.color!
: Theme.of(context).disabledColor),
onPressed: selectedFavouriteSongs.isNotEmpty
? () {
BlocProvider.of<FavouriteSongBloc>(context).add(
AddSelectedSongs(
favourite: widget.destinationFavourite!,
favouriteSongs: selectedFavouriteSongs,
socialMode: widget.socialMode));
}
: null,
),
],
),
)
],
),
body: BlocListener<FavouriteSongBloc, FavouriteSongState>(
listener: (context, state) {
if (state is SelectedFavouriteSuccess) {
Navigator.of(context).pop();
}
},
child: BlocBuilder<FavouriteSongBloc, FavouriteSongState>(
builder: (context, state) {
if (state is SongError) {
return const SomethingWentWrongScreen();
} else if (state is DownloadedSongListLoaded) {
if (state.favouriteSongs.isEmpty) {
return const NoResultFoundScreen(
title: 'သိမ်းထားသေားတရားတော်များ မရှိသေးပါ။',
subTitle:
'ကျေးဇူးပြု၍ တရားတော်များကို အစီအစဉ်စာရင်းထဲသို့ ထည့်ပါ။',
);
}
favouriteSongs = state.favouriteSongs;
return ListView.separated(
separatorBuilder: (BuildContext context, int index) =>
const Divider(height: 1),
itemCount: state.favouriteSongs.length,
itemBuilder: (_, int index) {
return Material(
child: ListTile(
minLeadingWidth: 0,
onTap: () {
setState(() {
favouriteSongs[index].isSelected =
!favouriteSongs[index].isSelected;
if (favouriteSongs[index].isSelected == true) {
selectedFavouriteSongs.add(favouriteSongs[index]
.copyWith(isSelected: true));
} else if (favouriteSongs[index].isSelected ==
false) {
selectedFavouriteSongs.removeWhere((element) =>
element.id == favouriteSongs[index].id);
}
});
},
title: TitleWidget(
favouriteSong: favouriteSongs[index],
),
subtitle:
SubTitleWidget(favouriteSong: favouriteSongs[index]),
trailing: favouriteSongs[index].isSelected
? Icon(
Icons.check_circle,
color: Theme.of(context).primaryColor,
)
: const Icon(Icons.check_circle_outline),
),
);
},
);
}
return const CircularProgressIndicatorWidget();
},
),
),
);
}
}
You can wrap DraggableScrollableSheet with ClipRRect with providing borderRadius.
builder: (BuildContext context) {
return ClipRRect(
borderRadius: const BorderRadius.only(
topLeft: Radius.circular(_radius),
topRight: Radius.circular(_radius),
),
child: DraggableScrollableSheet(
This issue is coming from builder inner views, here it is from DownloadedDharmaSongScreen, You can also wrap it with ClipRRect instead of using it on builder.
builder: (context, scrollController) {
return Column(
mainAxisSize: MainAxisSize.min,
children: [
ClipRRect(
borderRadius: const BorderRadius.only(
topLeft: Radius.circular(_radius),
topRight: Radius.circular(_radius),
),
child:DownloadedDharmaSongScreen(

Why StatefulWidget doesn't update when setState called?

I'm writing a program that uses floatingActionButton.
When OriginFloatingActionButton() called, showDialog() is called in the method.
Profile calls first.
#immutable
class Profile extends StatefulWidget {
const Profile({Key? key}) : super(key: key);
#override
_Profile createState() => _Profile();
}
class _Profile extends State<Profile> {
#override
Widget build(BuildContext context) {
return Scaffold(
floatingActionButton: OriginFloatingActionButton(),
.......
);
}
}
Below code is showing floatingActionButton, and show dialog when it pushed.
In this dialog, when ElevatedButton pushed, add strings list element with setState.
However amount of element in ListView.builder isn't updated.
When I close dialog and re-open it, it updated.
How can I update ListView.builder when push ElevatedButton.
class OriginFloatingActionButton extends StatefulWidget {
const OriginFloatingActionButton({Key? key}) : super(key: key);
#override
_OriginFloatingActionButton createState() => _OriginFloatingActionButton();
}
class _OriginFloatingActionButton extends State<OriginFloatingActionButton> {
List<String> strings = <String>[
"abc"
];
#override
Widget build(BuildContext context) {
return Container(
margin: const EdgeInsets.only(bottom: 30.0, right: 30),
width: 140,
height: 55,
child: SingleChildScrollView(
child: FloatingActionButton.extended(
label: const Text("Post"),
icon: const Icon(Icons.add),
backgroundColor: Colors.blue,
foregroundColor: Colors.white,
onPressed: () {
showDialog(
context: context,
builder: (BuildContext context) {
return Dialog(
elevation: 16,
child: Container(
height: 700,
width: 500,
child: Center(
child: Column(
children: <Widget>[
Center(
child: Row(
mainAxisSize: MainAxisSize.min,
children: [
SizedBox(
width: 300,
child: Expanded(
child: ListView.builder(
shrinkWrap: true,
itemCount:
strings.length,
itemBuilder:
(BuildContext context,
int index) {
return TextField(
decoration: InputDecoration(
label: Text(
"Artist Name " +
index
.toString()),
border:
const OutlineInputBorder()),
);
}))),
const SizedBox(
width: 5,
),
ElevatedButton(
child: const Icon(Icons.add),
style: ElevatedButton.styleFrom(
primary: Colors.white,
onPrimary: Colors.black,
shape: const CircleBorder(
side: BorderSide(
color: Colors.black,
width: 1,
style: BorderStyle.solid))),
onPressed: () {
setState(() {
if (mounted) {
strings
.add("ABC");
}
});
},
),
........
Is this because that I call OriginFloatingActionButton() in floatingActionButton:?
So far no errors have occurred.
How can I update the ListView without refreshing the Dialog?
Use StatefulBuilder to use setState inside Dialog
showDialog(
context: context,
builder: (context) {
return StatefulBuilder(
builder: (context, setState) {
return AlertDialog(
title: Text("Title of Dialog"),
content: Text(contentText),
actions: <Widget>[
TextButton(
onPressed: () => Navigator.pop(context),
child: Text("Cancel"),
),
TextButton(
onPressed: () {
setState(() {
///this will update
});
},
child: Text("Change"),
),
],
);
},
);
},
);

Two ChangeNotifierProvider on two different pages

How can I provide two ChangeNotifierProvider for different pages.
The first page works fine but when I click button and switch to the other side the Provider is not working properly and show me this error:
Error: Could not find the correct Provider above this SecondPage Widget. My code:
Main:
void main() => runApp(App());
class App extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
home: MultiProvider(
providers: [
ChangeNotifierProvider(
create: (context) => UserListViewModel(),
),
ChangeNotifierProvider(
create: (context) => AnimalViewModel(),
)
],
child: UserListPage(),
)
);
}
}
UserListPage:
class UserListPage extends StatefulWidget {
#override
_UserListPageState createState() => _UserListPageState();
}
class _UserListPageState extends State<UserListPage> {
#override
void initState() {
super.initState();
Provider.of<UserListViewModel>(context, listen: false).fetchUsers("");
}
#override
Widget build(BuildContext context) {
final vm = Provider.of<UserListViewModel>(context);
return Scaffold(
appBar: AppBar(
title: Text("Movies")
),
body: Container(
padding: EdgeInsets.all(10),
width: MediaQuery.of(context).size.width,
height: MediaQuery.of(context).size.height,
child: Column(children: <Widget>[
Container(
padding: EdgeInsets.only(left: 10),
decoration: BoxDecoration(
color: Colors.grey,
borderRadius: BorderRadius.circular(10)
),
child: RaisedButton(
onPressed: () {
Navigator.push(
context,
MaterialPageRoute(builder: (context) => SecondPage()),
);
},
textColor: Colors.white,
padding: const EdgeInsets.all(0.0),
child: Container(
decoration: const BoxDecoration(
gradient: LinearGradient(
colors: <Color>[
Color(0xFF0D47A1),
Color(0xFF1976D2),
Color(0xFF42A5F5),
],
),
),
padding: const EdgeInsets.all(10.0),
child:
const Text('Gradient Button', style: TextStyle(fontSize: 20)),
),
),
),
Expanded(
child: UserList(users: vm.users))
])
)
);
}
}
SecondPage:
class _SecondPageState extends State<SecondPage> {
#override
void initState() {
super.initState();
}
#override
Widget build(BuildContext context) {
final vm = Provider.of<AnimalViewModel>(context);
return Scaffold(
appBar: AppBar(
title: Text("Animals")
),
body: Container(
padding: EdgeInsets.all(10),
width: MediaQuery.of(context).size.width,
height: MediaQuery.of(context).size.height,
child: Column(children: <Widget>[
Container(
padding: EdgeInsets.only(left: 10),
decoration: BoxDecoration(
color: Colors.grey,
borderRadius: BorderRadius.circular(10)
),
child: RaisedButton(
onPressed: () {
vm.setName = 'BumBum';
},
textColor: Colors.white,
padding: const EdgeInsets.all(0.0),
child: Container(
decoration: const BoxDecoration(
gradient: LinearGradient(
colors: <Color>[
Color(0xFF0D47A1),
Color(0xFF1976D2),
Color(0xFF42A5F5),
],
),
),
padding: const EdgeInsets.all(10.0),
child:
const Text('Gradient Button', style: TextStyle(fontSize: 20)),
),
),
),
Expanded(
child: Text(vm.getName))
])
)
);
}
}
You need to move your MultiProvider above MaterialApp. Like this:
MultiProvider(
providers: [
ChangeNotifierProvider(
create: (context) => UserListViewModel(),
),
ChangeNotifierProvider(
create: (context) => AnimalViewModel(),
)
],
child: MaterialApp(
home: UserListPage(),
),
),
The reason you're getting the error is the home widget is a route and that's what MultiProvider wraps. So when you navigate from that route to SecondPage, that route is gone and it can not access MultiProvider

Persistent bottom sheet form data

I have one form on a bottom sheet. It's opened on click of one button. It can be closed when the user clicks outside the form. I want to maintain the form data if the user reopens the form. I don't want to assign each form field value explicitly. Is there any other way of saving the form state and reusing it while creating the bottom sheet again?
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
));}
);
So I finally found one of the best approaches for maintaining the state using Provider. I also explored other ways such as BLOC but it was very verbose for it. We can use BLOC for other cases but Provider is a better solution in case of a bottom 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);
},
)),
));
}
}

How do I navigator.push a showModalBottomSheet for flutter?

How do I navigator.push a showModalBottomSheet for flutter?
class SetRepeatButton extends StatefulWidget {
#override
_SetRepeatButtonState createState() => _SetRepeatButtonState();
}
class _SetRepeatButtonState extends State<SetRepeatButton> {
void _repeatMenu(BuildContext context) {
showModalBottomSheet(
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(20.0),
),
backgroundColor: Colors.white,
context: context,
builder: (builder) => Padding(
padding: const EdgeInsets.all(20.0),
child: Container(
height: MediaQuery.of(context).copyWith().size.height / 3,
child: Column(
children: <Widget>[
],
),
),
)
);
}
#override
Widget build(BuildContext context) {
return Builder(
builder: (builder) => FlatButton(
color: Colors.white,
textColor: Colors.grey,
disabledColor: Colors.grey,
disabledTextColor: Colors.black,
onPressed: () async {
final result = await Navigator.push(
context,
MaterialPageRoute(builder: (context) => _repeatMenu()),
);
},
child: Row(
),
),
);
}
}
what do you want to achieve?
if just to show the bottomsheet, just call the function in on press.
but it will be a little different if you want to catch the variable passed from the bottomsheet to the main context
you can try like this to show bottomsheet
import 'package:flutter/material.dart';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
home: SetRepeatButton(),
);
}
}
class SetRepeatButton extends StatefulWidget {
#override
_SetRepeatButtonState createState() => _SetRepeatButtonState();
}
class _SetRepeatButtonState extends State<SetRepeatButton> {
void _repeatMenu(BuildContext context) {
showModalBottomSheet(
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(20.0),
),
backgroundColor: Colors.white,
context: context,
builder: (builder) => Padding(
padding: const EdgeInsets.all(20.0),
child: Container(
height: MediaQuery.of(context).copyWith().size.height / 3,
child: Column(
children: <Widget>[
Text('Text'),
],
),
),
));
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('Text'),
),
body: Center(
child: RaisedButton(
color: Colors.white,
textColor: Colors.grey,
disabledColor: Colors.grey,
disabledTextColor: Colors.black,
onPressed: () async {
_repeatMenu(context);
},
child: Text('Text'),
),
),
);
}
}