Onboarding on initstate not working
Macacoazul01 opened this issue · comments
Gianluca Bettega commented
I tried to implement the onboarding overlay with WidgetsBinding.instance!.addPostFrameCallback
as you suggest on the readme, but everytime i run the code i'm getting the error Null check operator used on a null value
on the line onboarding!.show();
:
the code i'm testing (the sample code of the package):
import 'package:flutter/material.dart';
import 'package:onboarding_overlay/onboarding_overlay.dart';
void main() {
runApp(App());
}
class App extends StatefulWidget {
final GlobalKey<OnboardingState> onboardingKey = GlobalKey<OnboardingState>();
@override
_AppState createState() => _AppState();
}
class _AppState extends State<App> {
late List<FocusNode> focusNodes;
@override
void initState() {
super.initState();
focusNodes = List<FocusNode>.generate(
6,
(int i) => FocusNode(debugLabel: 'Onboarding Focus Node $i'),
growable: false,
);
WidgetsBinding.instance!.addPostFrameCallback((timeStamp) {
final OnboardingState? onboarding = Onboarding.of(context);
onboarding!.show();
});
}
@override
Widget build(BuildContext context) => MaterialApp(
home: Onboarding(
key: widget.onboardingKey,
steps: <OnboardingStep>[
OnboardingStep(
focusNode: focusNodes[0],
title: 'Tap anywhere to continue Tap anywhere to continue',
titleTextColor: Colors.black,
bodyText: 'Tap anywhere to continue Tap anywhere to continue',
labelBoxPadding: const EdgeInsets.all(16.0),
labelBoxDecoration: BoxDecoration(
shape: BoxShape.rectangle,
borderRadius: const BorderRadius.all(Radius.circular(8.0)),
color: const Color(0xFF00E1FF),
border: Border.all(
color: const Color(0xFF1E05FB),
width: 1.0,
style: BorderStyle.solid,
)),
arrowPosition: ArrowPosition.bottomCenter,
hasArrow: true,
hasLabelBox: true,
fullscreen: true,
),
OnboardingStep(
focusNode: focusNodes[1],
title: 'Tap only here to increment & continue',
bodyText: 'Tap only here to increment & continue',
shape: const CircleBorder(),
fullscreen: false,
overlayColor: Colors.blue.withOpacity(0.9),
overlayShape: const CircleBorder(),
),
OnboardingStep(
focusNode: focusNodes[2],
title: 'Easy to customize',
bodyText: 'Easy to customize',
overlayColor: Colors.red.withOpacity(0.9),
labelBoxPadding: const EdgeInsets.all(16.0),
labelBoxDecoration: BoxDecoration(
shape: BoxShape.rectangle,
borderRadius: const BorderRadius.all(Radius.circular(8.0)),
color: const Color(0xFF1100FF),
border: Border.all(
color: const Color(0xFFE2FB05),
width: 1.0,
style: BorderStyle.solid,
)),
arrowPosition: ArrowPosition.bottomCenter,
hasArrow: true,
hasLabelBox: true,
textAlign: TextAlign.center,
),
OnboardingStep(
focusNode: focusNodes[3],
title: 'Add steps for any widget',
bodyText: 'Add steps for any widget',
overlayColor: Colors.green.withOpacity(0.9),
),
OnboardingStep(
focusNode: focusNodes[4],
title: 'Settings',
shape: const CircleBorder(),
bodyText:
'Click here to access settings such as dark mode, daily limit, etc',
fullscreen: false,
overlayColor: Colors.black.withOpacity(0.8),
overlayShape: const CircleBorder(),
),
OnboardingStep(
focusNode: focusNodes[5],
title: "Or no widget at all! You're all done!",
bodyText: "Or no widget at all! You're all done!",
margin: EdgeInsets.zero,
),
],
child: Home(
focusNodes: focusNodes,
),
),
);
}
class Home extends StatefulWidget {
const Home({
Key? key,
required this.focusNodes,
}) : super(key: key);
final List<FocusNode> focusNodes;
@override
_HomeState createState() => _HomeState();
}
class _HomeState extends State<Home> {
late int _counter;
@override
void initState() {
super.initState();
_counter = 0;
}
@override
void dispose() {
super.dispose();
}
void _increment(BuildContext context) {
setState(() {
_counter++;
Onboarding.of(context)!.show();
});
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
leading: IconButton(
focusNode: widget.focusNodes[4],
icon: const Icon(Icons.menu),
onPressed: () {},
),
title: Focus(
focusNode: widget.focusNodes[3],
child: const Text('Title'),
),
),
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Focus(
focusNode: widget.focusNodes[0],
child: const Text('You have pushed the button this many times:'),
),
Focus(
focusNode: widget.focusNodes[2],
child: Text(
'$_counter',
style: Theme.of(context).textTheme.headline4,
),
),
],
),
),
floatingActionButton: FloatingActionButton(
focusNode: widget.focusNodes[1],
onPressed: () {
_increment(context);
},
child: const Icon(Icons.add),
),
);
}
}
Gianluca Bettega commented
found what was wrong...
the widgetsBinding should be on the home class
.
.
.
class Home extends StatefulWidget {
const Home({
Key? key,
required this.focusNodes,
}) : super(key: key);
final List<FocusNode> focusNodes;
@override
_HomeState createState() => _HomeState();
}
class _HomeState extends State<Home> {
late int _counter;
@override
void initState() {
super.initState();
WidgetsBinding.instance!.addPostFrameCallback((timeStamp) {
final OnboardingState? onboarding = Onboarding.of(context);
onboarding!.show();
});
_counter = 0;
}
.
.
.
Zlati Pehlivanov commented
yes, you would need to show the onboarding in a nested widget context.
haven't you received an exception like this "Accessing the OnboardingState with Onboarding.of(context) needs an Onboarding widget ancestor"