如何使frameBuilder和loadingBuilder在Image.network中协同工作?

问题描述

如何使frameBuilder和loadingBuilder一起工作?

“ loadingBuilder”始终有效(无论是否带有frameBuilder),但“ frameBuilder”仅在单独使用时才有效(即,将loadBuilder注释掉)。

该文档讨论了如何使用loadBuilder“链接” frameBuilder,这并不是内部发生的事情还是我们必须考虑的事情。

Image.network(_imageUrl,height: 400,width: MediaQuery.of(context).size.width,fit: BoxFit.fitWidth,frameBuilder: (BuildContext context,Widget child,int frame,bool wasSynchronouslyLoaded) {
        if (wasSynchronouslyLoaded) return child;
        return AnimatedOpacity(
                opacity: frame == null ? 0 : 1,duration: Duration(seconds: 5),curve: Curves.eaSEOut,child: child,);
    },loadingBuilder: (BuildContext context,ImageChunkEvent loadingProgress) {
        if (loadingProgress == null) return child;
        return Center(
            child: CircularProgressIndicator(
                        value: loadingProgress.expectedTotalBytes != null ?
                        loadingProgress.cumulativeBytesLoaded / loadingProgress.expectedTotalBytes :
                        null,),errorBuilder: (BuildContext context,Object exception,StackTrace stackTrace) {
        return Text('Failed to load image');
    },

编辑:

确切发生的事情:

情况1:当loadBuilder为ALONE时,显示CircularProgressIndicator,并且加载过程完成,然后指示器消失,并且显示的加载图像没有褪色。 (完美)

情况2:当frameBuilder为ALONE时,图像需要花费一定的时间加载(当然有指示符),然后加载的图像将按预期逐渐显示。 (完美)

情况3:同时启用frameBuilder和loadingBuilder时,情况1完全发生,而图像没有任何褪色。 (错)

预期的行为:

正在加载过程中会显示指示器,然后消失,并且图像会显示出褪色效果

我需要修复此代码并找出问题出在哪里。

解决方法

似乎“链接”是自动发生的,但您仍然需要考虑它们链接在一起的结果。

它们不能一起工作的问题是因为当frame == null时,显示的是CircularProgressIndicator; AnimatedOpacity 仅在 frame 不为空时显示,因此其不透明度始终为 1,这意味着我们失去了淡出效果。

解决办法是在加载时设置opticity为0,加载时设置为1。

以下代码应该可以工作:

/// Flutter code sample for Image.frameBuilder

// The following sample demonstrates how to use this builder to implement an
// image that fades in once it's been loaded.
//
// This sample contains a limited subset of the functionality that the
// [FadeInImage] widget provides out of the box.

import 'package:flutter/material.dart';

void main() => runApp(MyApp());

/// This is the main application widget.
class MyApp extends StatelessWidget {
  static const String _title = 'Flutter Code Sample';

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: _title,home: MyStatefulWidget(),);
  }
}

bool loading = false;

/// This is the stateless widget that the main application instantiates.
class MyStatefulWidget extends StatefulWidget {
  MyStatefulWidget({Key key}) : super(key: key);

  @override
  MyStatefulWigdetState createState() => MyStatefulWigdetState();
}

class MyStatefulWigdetState extends State<MyStatefulWidget> {
  @override
  Widget build(BuildContext context) {
    return DecoratedBox(
      decoration: BoxDecoration(
        color: Colors.white,border: Border.all(),borderRadius: BorderRadius.circular(20),),child: Image.network(
        'https://flutter.github.io/assets-for-api-docs/assets/widgets/puffin.jpg',frameBuilder: (BuildContext context,Widget child,int frame,bool wasSynchronouslyLoaded) {
          if (wasSynchronouslyLoaded) {
            return child;
          }
          return AnimatedOpacity(
            child: child,opacity: loading ? 0 : 1,duration: const Duration(seconds: 3),curve: Curves.easeOut,);
        },loadingBuilder: (BuildContext context,ImageChunkEvent loadingProgress) {
          if (loadingProgress == null) {
            // The child (AnimatedOpacity) is build with loading == true,and then the setState will change loading to false,which trigger the animation
            WidgetsBinding.instance.addPostFrameCallback((_) {
              setState(() => loading = false);
            });

            return child;
          }
          loading = true;
          return Center(
            child: CircularProgressIndicator(
              value: loadingProgress.expectedTotalBytes != null
                  ? loadingProgress.cumulativeBytesLoaded /
                      loadingProgress.expectedTotalBytes
                  : null,);
  }
}