如何正确地为无状态小部件预缓存图像?

Vin*_*nzo 5 preload flutter

我试图避免图像加载延迟,导致它在我的无状态 SplashScreen 中弹出,但没有运气。我尝试加载图像main()并将其传递给构造函数,但没有任何更改。

我读了很多关于同一问题的答案,并且所有帖子都precacheImage在Stateful Widget 的扩展 State 类中使用,所以我尝试了它,但即使遵循答案示例和本文https://alex,didChangeDependencies结果仍然相同。 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),
                ),
              ),
            ],
          ),
        ),
      ),
    );
  }
}
Run Code Online (Sandbox Code Playgroud)

我找到了一个解决方法,如我的答案中所示,但是如果您没有一个有状态的小部件来预先缓存图像并将它们传递到使用它们的屏幕,那么问题仍然存在。

例如,在我的网站中,我设置了自己的导航器服务,这样屏幕就不会从有状态的小部件返回:

路线生成器

Route<dynamic> generateRoute(RouteSettings settings) {
  switch (settings.name) {
    case HomeRoute:
      return _getPageRoute((HomePage()));
    case AboutRoute:
      return _getPageRoute(AboutPage());
    case RetailerAccessRoute:
      return _getPageRoute(RetailerAccess());
  }
}
Run Code Online (Sandbox Code Playgroud)

所以我设置了两个中间页面HomePageImagePreloaderAboutPageImagePreloader返回了它们:

路线生成新

Route<dynamic> generateRoute(RouteSettings settings) {
  switch (settings.name) {
    case HomeRoute:
      return _getPageRoute((HomePageImagePreloader()));
    case AboutRoute:
      return _getPageRoute(AboutPageImagePreloader());
    case RetailerAccessRoute:
      return _getPageRoute(RetailerAccess());
  }
}
Run Code Online (Sandbox Code Playgroud)

关于PageImagePreloader:

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);
  }
}
Run Code Online (Sandbox Code Playgroud)

将必要的图像添加到“主页”并AboutPage构造函数中,但是当网站加载时,背景第一个背景图像仍然没有加载..所以我的解决方法在网络上不起作用..

我不敢相信像加载图像这样的基本操作必须如此复杂..让我觉得 Flutter 毕竟不是一个好的选择..你知道预缓存是否还不能在网络上运行吗?我在最新的开发频道..

非常感谢。

Vin*_*nzo 2

使precacheImage方法与我的第一次尝试结合使用的一种方法是将 SplashScreen 保持无状态。然后main()子进程(通常App())将是有状态的,以预先缓存所有需要的图像,并通过构造函数中的最终bgImage属性将它们传递到屏幕中。这样,所有加载的背景图像都不会闪烁。

main() 的孩子:

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);
...
Run Code Online (Sandbox Code Playgroud)

启动画面(无状态):

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),
                ),
              ),
            ],
          ),
        ),
      ),
    );
  }
}
Run Code Online (Sandbox Code Playgroud)