Reputation: 6458
I'm trying to avoid the image loading delay that makes it pop up in my stateless SplashScreen but with no luck.
I tried to load the image in main()
and pass it in to the constructor but had no changes.
I read quite a few answers on the same problem, and all post to use precacheImage
in didChangeDependencies
in extend State class of a Stateful Widget, so I tried it but still the result is the same even following answers examples and this article https://alex.domenici.net/archive/preload-images-in-a-stateful-widget-on-flutter.
class SplashScreen extends StatefulWidget {
@override
_SplashScreenState createState() => _SplashScreenState();
}
class _SplashScreenState extends State<SplashScreen> {
Image logo;
@override
void initState() {
super.initState();
logo = Image.asset(
'assets/notification.png',
height: 170,
width: 170,
);
}
@override
void didChangeDependencies() {
super.didChangeDependencies();
precacheImage(logo.image, context);
}
@override
Widget build(BuildContext context) {
return Scaffold(
backgroundColor: Colors.redAccent,
body: Center(
child: Padding(
padding: EdgeInsets.symmetric(vertical: 20),
child: Column(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: <Widget>[
SizedBox(
height: 150,
),
logo,
SizedBox(
height: 60,
),
Expanded(
child: Text(
AppLocalizations.instance.text('Splash screen message'),
textAlign: TextAlign.center,
style: TextStyle(
color: Colors.white,
fontSize: 25,
fontWeight: FontWeight.w500,
letterSpacing: 1.5),
),
),
],
),
),
),
);
}
}
I found a workaround as shown in my answer, but the problem persists if you don't have a stateful widget that pre caches images and pass them to the screen that uses them.
In my website for example I set my own Navigator service so screens don't get returned from a stateful widget:
Route<dynamic> generateRoute(RouteSettings settings) {
switch (settings.name) {
case HomeRoute:
return _getPageRoute((HomePage()));
case AboutRoute:
return _getPageRoute(AboutPage());
case RetailerAccessRoute:
return _getPageRoute(RetailerAccess());
}
}
So I set up two intermediate pages HomePageImagePreloader
and AboutPageImagePreloader
and returned those instead:
Route<dynamic> generateRoute(RouteSettings settings) {
switch (settings.name) {
case HomeRoute:
return _getPageRoute((HomePageImagePreloader()));
case AboutRoute:
return _getPageRoute(AboutPageImagePreloader());
case RetailerAccessRoute:
return _getPageRoute(RetailerAccess());
}
}
class AboutPageImagePreloader extends StatefulWidget {
@override
_AboutPageImagePreloaderState createState() => _AboutPageImagePreloaderState();
}
class _AboutPageImagePreloaderState extends State<AboutPageImagePreloader> {
Image bgImageDesktop;
Image bgImageMobile;
@override
void initState() {
super.initState();
bgImageDesktop = Image.asset('assets/aboutUsDesktopBg.jpg');
bgImageMobile = Image.asset('assets/aboutUsMobileBg2.jpg');
}
@override
void didChangeDependencies() {
super.didChangeDependencies();
precacheImage(bgImageDesktop.image, context);
precacheImage(bgImageMobile.image, context);
}
@override
Widget build(BuildContext context) {
return AboutPage(bgImageDesktop: bgImageDesktop, bgImageMobile: bgImageMobile);
}
}
Added the necessaries images to 'HomePage' and AboutPage
constructors but when website load up, background first bg image stil hasn't loaded.. so my workaround isn't working on web..
I can't believe that such a basic operation as loading an image has to be this complicated.. makes me think Flutter ain't such a good choice after all.. DO you know if pre caching isn't working on web yet? I'm on the latest dev channel..
Many thanks.
Upvotes: 5
Views: 4134
Reputation: 6458
One way to make precacheImage
method work in conjunction to my first try would be to leave SplashScreen stateless. Then main()
child ( usually App()
) will be stateful to precache all needed images and pass them in screens through a final bgImage
property in the constructor.
This way it all loads up with no flickering bg images.
class _FixitState extends State<Fixit> {
final FirebaseAnalytics analytics = FirebaseAnalytics();
Image logo;
Image loginBg;
@override
void initState() {
super.initState();
logo = Image.asset('assets/notification.png');
loginBg = Image.asset('assets/mainBg.png');
}
@override
void didChangeDependencies() {
super.didChangeDependencies();
precacheImage(logo.image, context);
precacheImage(loginBg.image, context);
}
@override
Widget build(BuildContext context) {
...
home: BlocBuilder<AuthenticationBloc, AuthenticationState>(
builder: (context, state) {
if (state is Unauthenticated) {
return LoginScreen(userRepository: widget._userRepository, bgImage: loginBg,);
}
...
return SplashScreen(logo: logo);
...
class SplashScreen extends StatelessWidget {
final Image logo;
const SplashScreen({Key key, @required this.logo}) : super(key: key);
@override
Widget build(BuildContext context) {
return Scaffold(
backgroundColor: Colors.redAccent,
body: Center(
child: Padding(
padding: EdgeInsets.symmetric(vertical: 20),
child: Column(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: <Widget>[
SizedBox(
height: 150,
),
Image(image: logo.image,height: 170,
width: 170,),
SizedBox(
height: 60,
),
Expanded(
child: Text(
AppLocalizations.instance.text('Splash screen message'),
textAlign: TextAlign.center,
style: TextStyle(
color: Colors.white,
fontSize: 25,
fontWeight: FontWeight.w500,
letterSpacing: 1.5),
),
),
],
),
),
),
);
}
}
Upvotes: 2