showBottomSheet throwing an error complaining no scaffold - flutter

Redirecting from LoginPage to OnBoarding. While onboarding click on a button need to show the bottom sheet. Using the Named routes for navigation.
Later in the Loginpage will be navigating to the onboarding using Navigator.pushNamed(context, '/onboarding'); to redirect.
here is the main.dart
void main() {
runApp(
MultiProvider(
providers: [ChangeNotifierProvider(create: (context) => ThemeModel())],
child: DevicePreview(
enabled: !kReleaseMode,
builder: (context) => MyApp(),
),
),
);
SystemChrome.setEnabledSystemUIOverlays([]);
}
class MyApp extends StatelessWidget {
// This widget is the root of your application.
#override
Widget build(BuildContext context) {
return MaterialApp(
locale: DevicePreview.of(context).locale, // <--- Add the locale
builder: DevicePreview.appBuilder, // <--- Add the builder
theme: Provider.of<ThemeModel>(context).currentTheme,
debugShowCheckedModeBanner: false,
initialRoute: '/',
routes: {
// When navigating to the "/" route, build the FirstScreen widget.
'/': (context) => LoginPage(),
// When navigating to the "/second" route, build the SecondScreen widget.
'/onboarding': (context) => OnboardingPage(),
'/home': (context) => Home(),
},
);
}
}
here is the code snippet for the buttonClick and then open the bottomsheet
_getButton(String hint, int index, BuildContext context) {
return MaterialButton(
height: 58,
minWidth: 340,
shape: RoundedRectangleBorder(borderRadius: new BorderRadius.circular(12)),
onPressed: () {
if(index == 1){
**showBottomSheet(
context: context,
builder: (context) => BasicProfileBottomSheetWidget());
}**
},
child: Text(
hint,
style: TextStyle(
fontSize: 22,
color: Colors.black,
),
),
color: Colors.white,
);
}
Here is my widget tree
Here is the error.
[38;5;248m════════ Exception caught by gesture ═══════════════════════════════════════════[39;49m
[38;5;244mThe following assertion was thrown while handling a gesture:[39;49m
No Scaffold widget found.
[38;5;244mOnboardingPage widgets require a Scaffold widget ancestor.[39;49m
[38;5;244mThe specific widget that could not find a Scaffold ancestor was: OnboardingPage[39;49m
[38;5;244mstate: _OnboardingPageState#4c2bb[39;49m
[38;5;244mThe ancestors of this widget were[39;49m
[38;5;244mMaterialApp[39;49m
[38;5;244mstate: _MaterialAppState#e362b[39;49m
[38;5;244mMyApp[39;49m
[38;5;244mdependencies: [_InheritedProviderScope<ThemeModel>][39;49m
[38;5;244mDevicePreview[39;49m
[38;5;244mstate: DevicePreviewState#2a192[39;49m
[38;5;244mChangeNotifierProvider<ThemeModel>[39;49m
[38;5;244mvalue: Instance of 'ThemeModel'[39;49m
[38;5;244mlistening to value[39;49m
[38;5;244mMultiProvider[39;49m
[38;5;244m...[39;49m
[38;5;248mTypically, the Scaffold widget is introduced by the MaterialApp or WidgetsApp widget at the top of your application widget tree.[39;49m
[38;5;244mWhen the exception was thrown, this was the stack[39;49m
[38;5;244m#0 debugCheckHasScaffold.<anonymous closure>[39;49m
[38;5;244m#1 debugCheckHasScaffold[39;49m
[38;5;244m#2 showBottomSheet[39;49m
[38;5;248m#3 _getButton.<anonymous closure>[39;49m
[38;5;244m#4 _InkResponseState._handleTap[39;49m
[38;5;244m...[39;49m
[38;5;244mHandler: "onTap"[39;49m
[38;5;244mRecognizer: TapGestureRecognizer#bb0ca[39;49m
[38;5;244mdebugOwner: GestureDetector[39;49m
[38;5;244mstate: ready[39;49m
[38;5;244mwon arena[39;49m
[38;5;244mfinalPosition: Offset(422.5, 960.5)[39;49m
[38;5;244mfinalLocalPosition: Offset(166.7, 29.3)[39;49m
[38;5;244mbutton: 1[39;49m
[38;5;244msent tap down[39;49m
[38;5;248m════════════════════════════════════════════════════════════════════════════════[39;49m

Try putting the Scaffold widget immediately after the MaterialApp, then OnBoardingPage can be inside the body of the Scaffold

Also, without using globalkey workaround below code worked..No clue on what is the actual root cause and fix though :)
showModalBottomSheet(
context: context,
isScrollControlled: true,
backgroundColor: Colors.transparent,
builder: (context) => Container(
height: MediaQuery.of(context).size.height * 0.50,
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"),
),
),
);

Related

Flutter Changenotifier provider getting disposed after closing and opening of bottom model sheet

In my Flutter app, I have this ChangeNotifier provider. On the homepage a ChangeNotifier is created.
ChangeNotifierProvider<UserTeam>(create: (_) => UserTeam()),
I am setting the value for this provider on button press using this code below.
late UserTeam _userTeam;
_userTeam = Provider.of<UserTeam>(context);
UserTeam _userTeam = UserTeam(userDetails: test, pageDetails: 3);
_userTeam.setUserTeam(_userTeam);
I am passing this ChangeNotifier provider to the bottom sheet.
showModalBottomSheet<dynamic>(
isScrollControlled: true,
shape: const RoundedRectangleBorder(borderRadius: BorderRadius.only(topLeft: Radius.circular(30), topRight: Radius.circular(30))),
backgroundColor: const Color(0xFFFFFFFF),
context: context,
builder: (BuildContext context2) {
return BlocProvider.value(
value: BlocProvider.of<AuthenticationBloc>(context),
child: BlocProvider.value(
value: BlocProvider.of<AuthBloc>(context),
child: MultiProvider(
providers: [
ChangeNotifierProvider<UserTeam?>(create: (_) => _userTeam),
],
child: StatefulBuilder(builder: (BuildContext context, StateSetter mystate) {
return SingleChildScrollView(
child: SizedBox(
height: MediaQuery.of(context).size.height - 50,
width: MediaQuery.of(context).size.width,
child: const teamSearch(),
),
);
}),
),
),
);
});
When opening the bottom model sheet for first time, ChangeNotifier UserTeam is available. After closing and opening it's getting disposed and throwing an error as this code shows below.
Another exception was thrown: A UserTeam was used after
being disposed.
Please help me with this.
The code is confusing Provider on which variable to use, please change variable names
final userTeam = Provider.of<UserTeam>(context);
UserTeam _userTeam = UserTeam(userDetails: 'test, pageDetails: 3);
userTeam.setUserTeam(_userTeam);
Rather than creating a whole new Provider later in showModalBottomSheet create a value provider
ChangeNotifierProvider.value<UserTeam?>(value: _userTeam),

Error saying that looking up a deactivated widget's ancestor is unsafe when using photo_view package

Apparently, I am having this error when I navigate to my photo view page and then back to the previous page.
======== Exception caught by widgets library =======================================================
The following assertion was thrown while finalizing the widget tree:
Looking up a deactivated widget's ancestor is unsafe.
At this point the state of the widget's element tree is no longer stable.
To safely refer to a widget's ancestor in its dispose() method, save a reference to the ancestor by calling dependOnInheritedWidgetOfExactType() in the widget's didChangeDependencies() method.
====================================================================================================
I have search for similar problems available in stackoverflow but I just cant find the related ones.
Below is part of the codes to route into the photo view page
FutureBuilder(
future: storage.downloadURL(annData.imagePath[index]),
builder: (BuildContext context,
AsyncSnapshot<String> snapshot) {
if(snapshot.connectionState == ConnectionState.done && snapshot.hasData)
{
return Card(
margin: EdgeInsets.zero,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(8),
),
child: InkWell(
onTap: (){
Navigator.of(context).push(MaterialPageRoute(
builder: (_) => GalleryWidget(
urlImages: snapshot.data!,
),
));
},
child: Container(
child: ClipRRect(
borderRadius: BorderRadius.circular(8),
child: Image.network(
snapshot.data!,
fit:BoxFit.cover,
),
),
),
),
);
}
if(snapshot.connectionState == ConnectionState.waiting)
{
return Loading();
}
return Container();
},
);
}),
),
] else ...[
Container(),
],
And here is my photo view page
class GalleryWidget extends StatelessWidget {
final String urlImages;
GalleryWidget({required this.urlImages});
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
backgroundColor: Theme.of(context).primaryColor,
elevation: 0.0,
),
body: Center(
child: PhotoView(
imageProvider: NetworkImage(urlImages),
),
),
);
}
}
After entering the gallerywidget page and back to the previous page, my existing functions such as delete or edit are all messed up. Please help me on this issue.
I try changing from stateful to stateless widget and the problems is still the same. Please forgive me as my knowledge on debugging is still at a beginner stage.
So while i was browsing the github repository for photo_view:
there is a comment saying to change the version in pubspec.yaml into this
photo_view:
git: https://github.com/bluefireteam/photo_view.git
after running pubget, i am not getting anymore issues. I hope this can help others.

flutter provider what is the difference with 'Context context' and 'context '

```
import 'package:a_class_flutter/provider/ac_score/ac_score_provider.dart';
import 'package:flutter/material.dart';
import 'package:flutter_screenutil/flutter_screenutil.dart';
import 'package:provider/provider.dart';
class ACScoreView extends StatelessWidget {
#override
Widget build(BuildContext context) {
return ChangeNotifierProvider(
create: (context) => ACScoreProvider(),
builder: (context, child) {
return Stack(
children: <Widget>[
_topMenu(context),
],
);
},
);
}
}
// Important!
Widget _topMenu(BuildContext context) {
return GestureDetector(
onTap: () {
context.read<ACScoreProvider>().showTopMenueStatus();
},
child: Container(
width: double.infinity,
height: double.infinity,
color: Colors.red,
child: Stack(
children: <Widget>[
Positioned(
child: AnimatedOpacity(
duration: Duration(microseconds: 100),
opacity:
context.watch<ACScoreProvider>().needShowTopMenue ? 1.0 : 0.0,
child: Container(
width: double.infinity,
height: ScreenUtil().setHeight(60),
color: Colors.black,
),
),
)
],
),
),
);
}
```
This is my code which is working well, but when I try to change Widget _topMenu(BuildContext context) to Widget _topMenu(context), Flutter gives me an error which is:
The following NoSuchMethodError was thrown building Builder(dirty, dependencies: [_InheritedProviderScope<ACScoreProvider>]): Class 'StatelessElement' has no instance method 'watch'. Receiver: Instance of 'StatelessElement'. Tried calling: watch<ACScoreProvider>().The relevant error-causing widget was ChangeNotifierProvider<ACScoreProvider> package:a_class_flutter/…/ac_score/ac_score.dart:9.
Why missing BuildContext declaration could cause this error? Do I need to put every context with BuildContext?
From the provider docs:
The easiest way to read a value is by using the extension methods on [BuildContext]:
context.read<T>(), which returns T without listening to it
Writing just Widget _topMenu(context), the context parameter is inferred as a dynamic context not BuildContext context and hence you it does not have the extension method .read<T>() you are trying to call.
If it were inside a StatefulWidget, this wouldn't have been a problem because it's State class has a instance context (type BuildContext) property and so the extension method .read<T>() can be called on it.

Navigator and Provider conflict in flutter

sending data between screen using Provider with Navigator concept make a conflict
error after the run
The following ProviderNotFoundError was thrown building SecondRoute(dirty):
Error: Could not find the correct Provider above this SecondRoute Widget
To fix, please:
Ensure the Provider is an ancestor to this SecondRoute Widget
Provide types to Provider
Provide types to Consumer
Provide types to Provider.of()
Always use package imports. Ex: `import 'package:my_app/my_code.dart';
Ensure the correct context is being used.
https://www.ideone.com/xHXK5m
you can pass data like this put data in class
RaisedButton(
child: Text(‘Send data to the second page’),
onPressed: () {
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => SecondPage(
data: data,
)),
);
},
),
and recieve data like this
class SecondPage extends StatelessWidget {
final Data data;
SecondPage({this.data});
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(‘Constructor — second page’),
),
body: Container(
padding: EdgeInsets.all(12.0),
alignment: Alignment.center,
child: Column(
children: <Widget>[
Container(
height: 54.0,
padding: EdgeInsets.all(12.0),
child: Text(‘Data passed to this page:’,
style: TextStyle(fontWeight: FontWeight.w700))),
Text(‘Text: ${data.text}’),
Text(‘Counter: ${data.counter}’),
Text(‘Date: ${data.dateTime}’),
],
),
),
);
}
You can try placing whatever Provider value you have above the MaterialApp and thus the navigation or, when you push to a second page, provide the value again. Providers are scoped to widget trees, so this is expected behavior.
As an example, to pass a value to another route, you could do something like
onPressed: () {
Navigator.of(context).push(MaterialPageRoute(builder: (context) {
final foo = 'foo';
Provider<String>.value(
value: foo,
child: NewPage(),
);
}));
},
And then just consume it like regular in the NewPage route.
Try this code:
MaterialApp(
title: 'Navigation Basics',
home: ChangeNotifierProvider(
builder: (context) => Data(),
child: FirstRoute(),
))
Delete ChangeNotifierProvider in FirstRoute

Permanent Persistent Bottom sheet flutter

I want my bottom sheet to stay on the screen till I close it from a code. Normally the bottom sheet can be closed by pressing back button(device or appbar) or even just by a downward gesture. How can I disable that?
_scaffoldKey.currentState
.showBottomSheet<Null>((BuildContext context) {
final ThemeData themeData = Theme.of(context);
return new ControlBottom(
songName: songName,
url: url,
play: play,
pause: pause,
state: test,
themeData: themeData,
);
}).closed.whenComplete((){
});
Control botton is a different widget.
Scaffold now has a bottom sheet argument and this bottom sheet cannot be dismissed by swiping down the screen.
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(....),
bottomSheet: Container(
child: Text('Hello World'),
),
);
}
Also you can use WillPopScope Widget to control pressing back button:
Widget _buildBottomSheet() {
return WillPopScope(
onWillPop: () {
**here you can handle back button pressing. Just leave it empty to disable back button**
},
child: **your bottom sheet**
)),
);
}
You can remove the appbar back button by providing an empty container in leading property.
AppBar(
leading: Container(),
);
But we don't have any control over device back button & bottomsheet will disappear on back pressed.
One of the many alternative approach could be using a stack with positioned & opacity widget
Example :
Stack(
children: <Widget>[
// your code here
Positioned(
left: 0.0,
right: 0.0,
bottom: 0.0,
child: Opacity(
opacity: _opacityLevel,
child: Card(
child: //Your Code Here,
),
),
),
// your code here
],
);
You can change _opacityLevel from 0.0 to 1.0 when a song is selected.
From what I can make out from your code is that you will be having a listView on top & music controls on the bottom. Make sure to add some Padding at the end of listView so that your last list item does not stay hidden behind your music controller card when you have scrolled all the way down.
If you want to further customize the look & feel of your music controller. You could use animationController or sizeAnimation to slide it from the bottom like a bottomSheet.
I hope this helps.
Add this parameters to showmodalbottomsheet,
isDismissible: false, enableDrag: false,
I wanted a bottomsheet that is draggable up and down, but does not close. So, first of all I created a function for my modalBottomSheet.
Future modalBottomSheetShow(BuildContext context) {
return showModalBottomSheet(
backgroundColor: Colors.transparent,
context: context,
builder: (context) => buildSheet(),
isDismissible: false,
elevation: 0,
);
}
Next, I used .whenComplete() method of showModalBottomSheet() to recursively call the modalBottomSheetShow() function.
Future modalBottomSheetShow(BuildContext context) {
return showModalBottomSheet(
backgroundColor: Colors.transparent,
context: context,
builder: (context) => buildSheet(),
isDismissible: false,
elevation: 0,
).whenComplete(() => modalBottomSheetShow(context));
}
Next, I simply call the modalBottomSheetShow() whenever I wanted a bottomsheet. It cannot be closed, until the recursion ends. Here is the entire code for reference:
import 'package:flutter/material.dart';
import 'package:google_maps_flutter/google_maps_flutter.dart';
class HomePage extends StatefulWidget {
const HomePage({Key? key}) : super(key: key);
static const idScreen = "HomePage";
#override
State<HomePage> createState() => _HomePageState();
}
#override
void initState() {
super.initState();
WidgetsBinding.instance.addPostFrameCallback((_) async {
modalBottomSheetShow(context);
});
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
toolbarHeight: 0,
elevation: 0,
backgroundColor: Colors.black,
),
);
}
Widget buildSheet() {
return DraggableScrollableSheet(
initialChildSize: 0.6,
builder: (BuildContext context, ScrollController scrollController) {
return Container(
decoration: BoxDecoration(color: Colors.white, boxShadow: [
BoxShadow(
color: Color(0x6C000000),
spreadRadius: 5,
blurRadius: 20,
offset: Offset(0, 0),
)
]),
padding: EdgeInsets.all(16),
);
},
);
}
Future modalBottomSheetShow(BuildContext context) {
return showModalBottomSheet(
backgroundColor: Colors.transparent,
context: context,
builder: (context) => buildSheet(),
isDismissible: false,
elevation: 0,
).whenComplete(() => modalBottomSheetShow(context));
}
}