I'M currently working on a to-do app following a tutorial
this is the checkbox part
I'm trying to lift it's state up the tree, but when I do so the stateless widget just keeps rebuilding non stop ,
I tried adding key , adding const converting it to stateful but nothing seems to work
it also doesn't provide me with any kind of error or exceptions messages
note : when I set the onChecked to null the statelessWidget runs twice when it should only build once..
below is the code:
import 'package:flutter/material.dart';
class TaskTile extends StatefulWidget {
#override
_TaskTileState createState() => _TaskTileState();
}
class _TaskTileState extends State {
bool isChecked = false;
#override
Widget build(BuildContext context) {
return ListTile(
title: Text(
"Complete Todoey",
style: TextStyle(
decoration: isChecked == true
? TextDecoration.lineThrough
: TextDecoration.none),
),
trailing: TaskCheckBox(
checkBoxState: isChecked,
toggleCheckBoxState:
(bool checkBoxState) {
Future.delayed(Duration.zero,
() async {
setState(() {
print(
"===================$isChecked==============$checkBoxState======================");
isChecked = checkBoxState;
});
});
}),
);
}
}
class TaskCheckBox extends StatelessWidget {
const TaskCheckBox(
{Key? key,
required this.checkBoxState,
required this.toggleCheckBoxState})
: super(key: key);
final bool checkBoxState;
final Function toggleCheckBoxState;
#override
Widget build(BuildContext context) {
print(
"=====================================$checkBoxState+++++++++++++++++++++++++++++++++++++++++");
return Checkbox(
value: checkBoxState,
onChanged:
null, // toggleCheckBoxState(checkBoxState),
);
}
}
a snip from the console output :
Performing hot restart...
Syncing files to device Android SDK built for x86...
I/flutter ( 3401): ===================false==============false======================
I/flutter ( 3401): =====================================false+++++++++++++++++++++++++++++++++++++++++
I/flutter ( 3401): ===================false==============false======================
I/flutter ( 3401): =====================================false+++++++++++++++++++++++++++++++++++++++++
I/flutter ( 3401): ===================false==============false======================
I/flutter ( 3401): =====================================false+++++++++++++++++++++++++++++++++++++++++
I/flutter ( 3401): ===================false==============false======================
I/flutter ( 3401): =====================================false+++++++++++++++++++++++++++++++++++++++++
I/flutter ( 3401): ===================false==============false======================
I/flutter ( 3401): =====================================false+++++++++++++++++++++++++++++++++++++++++
a snip from the output when onChanged is set to null :
Restarted application in 2,694ms.
I/flutter ( 3401): =====================================false+++++++++++++++++++++++++++++++++++++++++
I/flutter ( 3401): =====================================false+++++++++++++++++++++++++++++++++++++++++
The purpose of setState is to tell the framework that a variable in the state has changed and the widget needs to be rebuilt to reflect that change. So calling setState calls the build function again, which in your case recalls your Future, which calls setState again, which triggers build and so on.
To fix this you could get rid of async function with Future.delayed since it's not needed there at all as well as putting print outside your setstate function.
Related
I'm kinda new to Flutter + Dart, for my second app I want to work on a spotify app for android.
I found the spotify sdk on pub dev and did my best to work with the docs from spotify and from pub dev but I dont get the token :(
First of all: I have a debug.keystore in my ../android/app/ and put the debug sha1 fingerprint on spotify console with a callback url.
I did everything from the spotify_sdk readme.
I tried it with different callback methods like:
redirectUrl: http://bundle_id/callback,
redirectUrl: bundle_id://callback,
redirectUrl: http://bundleid/auth,
and everything with the client_id and client_secret (because the docs are not clear for me what I should use).
It would be great if you guys could help out. I'm alone and dont have dev friends to ask D:
This is my code
import 'package:flutter/material.dart';
import 'package:spotify_sdk/spotify_sdk.dart';
void main() {
runApp(const MaterialApp(
home: HomePage(),
));
}
class HomePage extends StatefulWidget {
const HomePage({Key? key}) : super(key: key);
#override
State<HomePage> createState() => _HomePageState();
}
class _HomePageState extends State<HomePage> {
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text('spotify auth test'),
),
body: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Align(
alignment: Alignment.center,
child: ElevatedButton(
onPressed: getAccessToken,
child: const Text('GIMMI TOKEN PLS'),
),
),
],
),
);
}
Future<String> getAccessToken() async {
try {
var authenticationToken = await SpotifySdk.getAccessToken(
clientId: 'client_id',
redirectUrl: 'redirectUrl',
scope: 'app-remote-control, '
'user-modify-playback-state, '
'playlist-read-private, '
'playlist-modify-public,user-read-currently-playing');
print('Got a token: $authenticationToken');
return authenticationToken;
} catch (e) {
print('$e.code, message $e.message');
return Future.error('$e.code: $e.message');
} /*catch (e) {
print('not implemented');
return Future.error('not implemented');
}*/
}
}
And this is my error log message:
I/flutter ( 7987): ┌───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────
I/flutter ( 7987): │ #0 SpotifySdk._logException (package:spotify_sdk/spotify_sdk.dart:633:15)
package:spotify_sdk/spotify_sdk.dart:633
I/flutter ( 7987): │ #1 SpotifySdk.getAccessToken (package:spotify_sdk/spotify_sdk.dart:128:7)
package:spotify_sdk/spotify_sdk.dart:128
I/flutter ( 7987): ├┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄
I/flutter ( 7987): │ ⛔ getAccessToken failed with: Authentication went wrong
I/flutter ( 7987): │ ⛔ AUTHENTICATION_SERVICE_UNKNOWN_ERROR
I/flutter ( 7987): └───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────
I/flutter ( 7987): PlatformException(authenticationTokenError, Authentication went wrong, AUTHENTICATION_SERVICE_UNKNOWN_ERROR, null).code, message PlatformException(authenticationTokenError, Authentication went wrong, AUTHENTICATION_SERVICE_UNKNOWN_ERROR, null).message
E/flutter ( 7987): [ERROR:flutter/lib/ui/ui_dart_state.cc(198)] Unhandled Exception: PlatformException(authenticationTokenError, Authentication went wrong, AUTHENTICATION_SERVICE_UNKNOWN_ERROR, null).code: PlatformException(authenticationTokenError, Authentication went wrong, AUTHENTICATION_SERVICE_UNKNOWN_ERROR, null).message
E/flutter ( 7987):
I know that there are already two posts regarding this question, but I could not solve my issue looking at them. Probably because in my case the issue is different.
The code is the following. I want to load some data from the database while showing a loading page. After the data is loaded, I initialize the provider with the loaded data and then I move into a different page.
This code does not need to be in a StatefulWidget, but I try to put it in a StatefulWidget to solve the issue, but without success.
class _InitDBDataState extends State<_InitDBData> {
#override
Widget build(BuildContext context) {
_fetchData(context);
return const Center(child: const CircularProgressIndicator());
}
Future<void> _fetchData(BuildContext context) async {
print('fetching data...');
print('context: $context');
final initData = await DBService.service.getInitialData();
print('Data fetched');
print('context: $context');
Provider.of<DataProvider>(context, listen: false).init(initData);
Navigator.of(context).pushReplacementNamed(MainScreen.routeName);
}
}
I do not have any error if the application runs from scratch, but when I am doing a "Hot Reload" I get the following error pretty often, and it is annoying since I need to restart the application for each small change in the code.
I/flutter ( 9596): fetching data...
I/flutter ( 9596): context: _InitDBData(dirty, state: _InitDBDataState#46860)
I/flutter ( 9596): fetching data...
I/flutter ( 9596): context: _InitDBData(dirty, state: _InitDBDataState#55124)
I/flutter ( 9596): Data fetched
I/flutter ( 9596): context: _InitDBData
E/flutter ( 9596): [ERROR:flutter/lib/ui/ui_dart_state.cc(157)] Unhandled Exception: Looking up a deactivated widget's ancestor is unsafe.
E/flutter ( 9596): At this point the state of the widget's element tree is no longer stable.
E/flutter ( 9596): 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.
E/flutter ( 9596): #0 Element._debugCheckStateIsActiveForAncestorLookup.<anonymous closure>
package:flutter/…/widgets/framework.dart:3508
E/flutter ( 9596): #1 Element._debugCheckStateIsActiveForAncestorLookup
package:flutter/…/widgets/framework.dart:3522
E/flutter ( 9596): #2 Element.getElementForInheritedWidgetOfExactType
package:flutter/…/widgets/framework.dart:3588
E/flutter ( 9596): #3 Provider.of
package:provider/src/provider.dart:221
E/flutter ( 9596): #4 _InitDBDataState._fetchData
package:productive_diary/initScreen.dart:46
E/flutter ( 9596): <asynchronous suspension>
E/flutter ( 9596): #5 _InitDBDataState.build
I don't know why "fetching data..." is printed twice, and I have no clue on how to solve the issue.
I thought the issue was solved with the solution of Saman Salehi, but working in debug mode I had the same exception in the _fetchData function, that now is called in the function initState()
Exception has occurred.
FlutterError (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 got another error after applying the edits suggested by Stewie Griffin
.
The error is on the line Provider.of<DataProvider>(context, listen: false).init(initData);
I got it during a hot reload. It seems less common than the other error, so the answer of Stewie Griffin surely improved the stability of my Stewie Griffin
E/flutter (23815): [ERROR:flutter/lib/ui/ui_dart_state.cc(157)] Unhandled Exception: NoSuchMethodError: The getter 'owner' was called on null.
E/flutter (23815): Receiver: null
E/flutter (23815): Tried calling: owner
E/flutter (23815): #0 Object.noSuchMethod (dart:core-patch/object_patch.dart:53:5)
E/flutter (23815): #1 Provider.of
package:provider/src/provider.dart:193
E/flutter (23815): #2 _InitDBDataState._fetchData
package:productive_diary/initScreen.dart:49
E/flutter (23815): <asynchronous suspension>
E/flutter (23815): #3 _InitDBDataState.initState
Could you please help me?
First of all, never call async methods inside of build as mentioned. Build method is constantly rebuilt and it will cause your fetch method to be repeated like an infinite loop. After you fix that, you still get the same error because of this part:
Navigator.of(context).pushReplacementNamed(MainScreen.routeName);
You shouldn't call Navigator during build. Here is what you need to do:
Add this line to the top of your file to use SchedulerBinding:
import 'package:flutter/scheduler.dart';
Wrap Navigator with SchedulerBinding to wait for completing the state before navigating to another screen. Then, call your async method inside of initState.
class _InitDBDataState extends State<_InitDBData> {
#override
void initState() {
// Call your async method here
_fetchData();
super.initState();
}
Future<void> _fetchData() async {
print('fetching data...');
print('context: $context');
final initData = await DBService.service.getInitialData();
print('Data fetched');
print('context: $context');
Provider.of<DataProvider>(context, listen: false).init(initData);
// Wrap Navigator with SchedulerBinding to wait for rendering state before navigating
SchedulerBinding.instance.addPostFrameCallback((_) {
Navigator.of(context).pushReplacementNamed(MainScreen.routeName);
});
}
#override
Widget build(BuildContext context) {
return Center(child: CircularProgressIndicator());
}
}
Tip: You don't need to pass the context in a Stateful Widget because you can access it from everywhere.
You shouldn't use the build method for anything other than building UI. build can be called at any time even when it's not on the screen.
I would move the _fetchData to the initState so it wouldn't cause any conflict at the build method.
class _InitDBDataState extends State<_InitDBData> {
#override
void initState() {
super.initState();
_fetchData(context);
}
#override
Widget build(BuildContext context) {
return const Center(child: const CircularProgressIndicator());
}
Future<void> _fetchData(BuildContext context) async {
print('fetching data...');
print('context: $context');
final initData = await DBService.service.getInitialData();
print('Data fetched');
print('context: $context');
Provider.of<DataProvider>(context, listen: false).init(initData);
Navigator.of(context).pushReplacementNamed(MainScreen.routeName);
}
}
Navigator.pushReplacement(context,MaterialPageRoute(builder:(context) => WelcomeScreen()),);
|^| .wrap this code SchedulerBinding.instance!.addPostFrameCallback on above code.
like this below:
SchedulerBinding.instance!.addPostFrameCallback((_) {
Navigator.pushReplacement(
context,
MaterialPageRoute(builder: (context) => WelcomeScreen()),
);
});
Schedule a callback for the end of this frame.
Does not request a new frame.
This callback is run during a frame, just after the persistent frame
callbacks (which is when the main rendering pipeline has been
flushed). If a frame is in progress and post-frame callbacks haven't
been executed yet, then the registered callback is still executed
during the frame. Otherwise, the registered callback is executed
during the next frame.
The callbacks are executed in the order in which they have been added.
Post-frame callbacks cannot be unregistered. They are called exactly
once.
Before:
After
SampleCode Here i use rive: ^0.8.1 dartpackage
import 'package:flutter/material.dart';
import 'package:flutter/scheduler.dart';
import 'package:rive/rive.dart';
void main() {
WidgetsFlutterBinding.ensureInitialized();
runApp(MaterialApp(home: SimpleAnimation()));
}
setdata(BuildContext context) async {
await Future.delayed(const Duration(seconds: 5), () {
SchedulerBinding.instance!.addPostFrameCallback((_) {
Navigator.pushReplacement(
context,
MaterialPageRoute(builder: (context) => WelcomeScreen()),
);
});
});
}
class SimpleAnimation extends StatelessWidget {
const SimpleAnimation({Key? key, this.loading}) : super(key: key);
final bool? loading;
#override
Widget build(BuildContext context) {
setdata(context);
return Scaffold(
body: Center(
child: Container(
height: 200,
width: 200,
child: RiveAnimation.network(
'https://cdn.rive.app/animations/vehicles.riv',
),
),
),
);
}
}
class WelcomeScreen extends StatelessWidget {
const WelcomeScreen({Key? key}) : super(key: key);
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(),
body: Center(
child: Container(
child: Text(
"HOME PAGE",
style: TextStyle(fontSize: 50),
),
),
),
);
}
}
if it is caused by accessing ScaffoldMessenger by context then putting it inside a try catch will resolve context error.
try{
ScaffoldMessenger.of(_scaffoldKey.currentContext!).showSnackBar();
} catch(e){
print(e);
}
For this probleme you can use one of this two solutions :
first: add scheduler like this :
SchedulerBinding.instance!.addPostFrameCallback((_) {
Navigator.of(context).pushReplacementNamed(MainScreen.routeName);
});
second: add future delayed with some milliseconds like this :
Future.delayed(Duration(microseconds: 200))
.then((value) {
Navigator.of(context).pushReplacementNamed(MainScreen.routeName);
});
!!! But if you a lot of change of state in the same time this solutions may still give the same error.
if is the case try to use the second solution by augmenting the duration.
I'm trying to inject instances of services (that have been created in the same tree level) into another provider. But down the tree when accessing the provider, I get ProviderNotFoundException exception.
In the following code NotificationService depends on AuthService. Which needs to be passed in the constructor. Hence I inject it using Consumer and Provider.value as mentioned in the docs: https://pub.dev/documentation/provider/latest/provider/Consumer-class.html
Here is the pseudo-code:
return MultiProvider(
providers: [
Provider<AuthService>(
create: (ctx) => AuthService(_storage),
dispose: (ctx, v) => v.dispose(),
),
Consumer<AuthService>(
builder: (context, v, child) {
return Provider.value(
value: Provider<NotificationService>(
create: (ctx) => NotificationService(v),
dispose: (ctx, v) => v.dispose(),
),
child: child
);
},
)
],
child: MyApp()
);
Somewhere down the tree line, When trying to access the NotificationService instance, I get ProviderNotFoundException:
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
final NotificationService _ns = Provider.of<NotificationService>(context);
}
}
Error:
I/flutter ( 4614): ══╡ EXCEPTION CAUGHT BY WIDGETS LIBRARY ╞═══════════════════════════════════════════════════════════
I/flutter ( 4614): The following ProviderNotFoundException was thrown building MyApp(dirty, dependencies:
I/flutter ( 4614): [_DefaultInheritedProviderScope<AuthService>]):
I/flutter ( 4614): Error: Could not find the correct Provider<NotificationService> above this MyApp Widget
I/flutter ( 4614):
I/flutter ( 4614): To fix, please:
I/flutter ( 4614):
I/flutter ( 4614): * Ensure the Provider<NotificationService> is an ancestor to this MyApp Widget
I/flutter ( 4614): * Provide types to Provider<NotificationService>
I/flutter ( 4614): * Provide types to Consumer<NotificationService>
I/flutter ( 4614): * Provide types to Provider.of<NotificationService>()
I/flutter ( 4614): * Ensure the correct `context` is being used.
I/flutter ( 4614):
I don't fully understand this, and I'm pretty sure there is a mistake in the above code. What am I doing wrong?
The way you used Provider.value is invalid. But you don't actually need Consumer+Provider. You can do:
MultiProvider(
providers: [
Provider(create: (_) => A()),
Provider(create: (context) => B(Provider.of<A>(context, listen: false)),
],
)
I am tying to implement Firebase Authentication in my Flutter app, with the help of provider. First, I am checking whether the user is already signed in. If yes, I AM sending him to the home screen. Else I am sending him to the Login screen.
Please check my code below.
main.dart
import 'package:flutter/material.dart';
import 'package:customer/services/auth.dart';
import 'package:provider/provider.dart';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
// This widget is the root of your application.
#override
Widget build(BuildContext context) {
return ChangeNotifierProvider(
child: MaterialApp(
title: 'Customer App',
home: AuthWrapper(),
routes: {
'/account': (context) => AccountPage(),
},
), create: (BuildContext context) {
AuthService();
},
);
}
}
auth.dart
import 'package:firebase_auth/firebase_auth.dart';
import 'package:flutter/material.dart';
class AuthService with ChangeNotifier{
final FirebaseAuth _auth = FirebaseAuth.instance;
FirebaseUser _user=null;
//Sign in with username and password
Future signInWithEmail(String email, String password) async {
FirebaseUser user;
try {
AuthResult result = await _auth.signInWithEmailAndPassword(
email: email, password: password);
user = result.user;
if (user != null) {
print("Sign in success: " + user.email);
_user = user;
} else {
print("sign in failed");
_user = null;
}
} catch (e) {
print(e.toString());
}
finally{
notifyListeners();
}
}
//Get the current user
FirebaseUser getCurrentUser() {
return _user;
}
}
auth_wrapper.dart
import 'package:firebase_auth/firebase_auth.dart';
import 'package:flutter/material.dart';
import 'package:customer/pages/home.dart';
import 'package:customer/pages/login.dart';
import 'package:customer/services/auth.dart';
import 'package:provider/provider.dart';
class AuthWrapper extends StatelessWidget {
AuthWrapper() {}
#override
Widget build(BuildContext context) {
var currentUser =Provider.of<AuthService>(context, listen: false).getCurrentUser();
if (currentUser == null) {
return LoginPage();
} else {
return HomePage();
}
}
}
Unfortunately, when I run this app, i get the following error.
I/flutter ( 3364): The following ProviderNotFoundException was thrown building AuthWrapper(dirty):
I/flutter ( 3364): Error: Could not find the correct Provider<AuthService> above this AuthWrapper Widget
I/flutter ( 3364):
I/flutter ( 3364): To fix, please:
I/flutter ( 3364):
I/flutter ( 3364): * Ensure the Provider<AuthService> is an ancestor to this AuthWrapper Widget
I/flutter ( 3364): * Provide types to Provider<AuthService>
I/flutter ( 3364): * Provide types to Consumer<AuthService>
I/flutter ( 3364): * Provide types to Provider.of<AuthService>()
I/flutter ( 3364): * Ensure the correct `context` is being used.
I/flutter ( 3364):
I/flutter ( 3364): If none of these solutions work, please file a bug at:
I/flutter ( 3364): https://github.com/rrousselGit/provider/issues
I/flutter ( 3364):
I/flutter ( 3364): The relevant error-causing widget was:
[38;5;248mI/flutter ( 3364): AuthWrapper[39;49m
I/flutter ( 3364):
I/flutter ( 3364): When the exception was thrown, this was the stack:
[38;5;248mI/flutter ( 3364): #0 Provider.of[39;49m
[38;5;248mI/flutter ( 3364): #1 AuthWrapper.build[39;49m
[38;5;244mI/flutter ( 3364): #2 StatelessElement.build[39;49m
[38;5;244mI/flutter ( 3364): #3 ComponentElement.performRebuild[39;49m
[38;5;244mI/flutter ( 3364): #4 Element.rebuild[39;49m
[38;5;244mI/flutter ( 3364): #5 ComponentElement._firstBuild[39;49m
[38;5;244mI/flutter ( 3364): #6 ComponentElement.mount[39;49m
[38;5;244mI/flutter ( 3364): #7 Element.inflateWidget[39;49m
[38;5;244mI/flutter ( 3364): #8 Element.updateChild[39;49m
[38;5;244mI/flutter ( 3364): #9 SingleChildRenderObjectElement.mount[3
I am newly trying out the provider patter, whats really going on here?
You can do the following.
Change the create: (BuildContext context) to create: (_)
.You are not currently using the BuildContext thus it can be changed to _ which is just cleaner code
Secondly it does not seem that your function is returning the value to the create (I might be wrong on this). This is why the functional instantiation works better.
Examples from the provider package
ChangeNotifierProvider(create: (_) => Counter()),
Your code changes
So Change this
create: (BuildContext context) {
AuthService();
},
To this
create: (_) => AuthService();
References
Using Underscore
Provider Package - Examples taken from here
If any one can explain the process of this better please assist.
I'm working on a finance app and I'd like a custom textentry field and keyboard for currency entry with an inbuilt calculator.
I've tried using a BottomSheet, both persistent and modal. The modal behaviour is ideal, but it always shows a barrier. The persistent one is what I have now, using a focus node to show and hide it, but it's throwing strange errors:
I/flutter (30319): The following NoSuchMethodError was thrown while dispatching notifications for FocusNode:
I/flutter (30319): The method 'removeLocalHistoryEntry' was called on null.
I/flutter (30319): Receiver: null
I/flutter (30319): Tried calling: removeLocalHistoryEntry(Instance of 'LocalHistoryEntry')
I/flutter (30319):
I/flutter (30319): When the exception was thrown, this was the stack:
I/flutter (30319): #0 Object.noSuchMethod (dart:core/runtime/libobject_patch.dart:46:5)
I/flutter (30319): #1 LocalHistoryEntry.remove (package:flutter/src/widgets/routes.dart:296:12)
I/flutter (30319): #2 _NumpadFieldState.initState.<anonymous closure> (file:///D:/code/financepie/lib/widgets/numpad/numpadfield.dart:30:32)
...
In any case, the bottom sheet behaviour (dragging down) isn't really ideal to copy the android/ios soft keyboard. Any better solutions? Current code below:
import 'package:flutter/material.dart';
import 'numpad.dart';
class NumpadField extends StatefulWidget {
#override
_NumpadFieldState createState() {
return new _NumpadFieldState();
}
}
class _NumpadFieldState extends State<NumpadField> {
ValueNotifier<List<String>> state;
FocusNode focusNode;
PersistentBottomSheetController bottomSheetController;
#override initState() {
super.initState();
state = ValueNotifier<List<String>>([]);
state.addListener(() => setState((){}));
focusNode = FocusNode();
focusNode.addListener(() {
print(focusNode);
if (focusNode.hasFocus) {
bottomSheetController = showBottomSheet(
context: context,
builder: (context) => Numpad(state: state),
);
} else {
bottomSheetController?.close(); ///this line causing the error
}
});
}
#override dispose() {
state.dispose();
focusNode.dispose();
super.dispose();
}
#override
Widget build(BuildContext context) {
return GestureDetector(
onTap: () {
FocusScope.of(context).requestFocus(focusNode);
},
child: Container(
child: Text(state.value.fold<String>("", (str, e) => "$str $e")),
constraints: BoxConstraints.expand(height: 24.0),
decoration: BoxDecoration(
border: BorderDirectional(bottom: BorderSide())
),
),
);
}
}
bottomSheetController?.close(); is nullable. Since the line causes the error, you can add a null-check to prevent this issue.
else {
if(bottomSheetController != null)
bottomSheetController!.close();
}