从网络抖动中加载图像的更好方法

时间:2018-12-02 06:28:38

标签: flutter

我正在尝试从网络加载图像并将其显示在GridView中。我正在使用StatefulWidget并将图像加载到build方法中。但是据我了解,在build方法内进行网络调用不是很好。如何从BLoC文件中的网络下载图像,然后将下载的图像列表传递给小部件?下面是我当前的实现。

class MovieList extends StatefulWidget {
  @override
  State<StatefulWidget> createState() {
    return MovieListState();
  }
}

class MovieListState extends State<MovieList> {
  @override
  void initState() {
    super.initState();
    bloc.fetchAllMovies();
  }

  @override
  void dispose() {
    bloc.dispose();
    super.dispose();
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text('Popular Movies'),
      ),
      body: StreamBuilder(
        stream: bloc.allMovies,
        builder: (context, AsyncSnapshot<ItemModel> snapshot) {
          if (snapshot.hasData) {
            return buildList(snapshot);
          } else if (snapshot.hasError) {
            return Text(snapshot.error.toString());
          }
          return Center(child: CircularProgressIndicator());
        },
      ),
    );
  }

  Widget buildList(AsyncSnapshot<ItemModel> snapshot) {
    return GridView.builder(
        itemCount: snapshot.data.results.length,
        gridDelegate:
        new SliverGridDelegateWithFixedCrossAxisCount(crossAxisCount: 2),
        itemBuilder: (BuildContext context, int index) {
          return GridTile(
            child: InkResponse(
              enableFeedback: true,
              child: Image.network(
                'https://image.tmdb.org/t/p/w185${snapshot.data
                    .results[index].poster_path}',
                fit: BoxFit.cover,
              ),
              onTap: () => openDetailPage(snapshot.data, index),
            ),
          );
        });
  }

  openDetailPage(ItemModel data, int index) {
    Navigator.push(
      context,
      MaterialPageRoute(builder: (context) {
        return MovieDetailBlocProvider(
          child: MovieDetail(
            title: data.results[index].title,
            posterUrl: data.results[index].backdrop_path,
            description: data.results[index].overview,
            releaseDate: data.results[index].release_date,
            voteAverage: data.results[index].vote_average.toString(),
            movieId: data.results[index].id,
          ),
        );
      }),
    );
  }
}

5 个答案:

答案 0 :(得分:6)

我建议您使用 https://pub.dartlang.org/packages/cached_network_image

这对我的情况确实很有效。

r中的简单代码示例

CachedNetworkImage(
   imageUrl: "http://via.placeholder.com/350x150",
   placeholder: CircularProgressIndicator(),
   errorWidget: Icon(Icons.error),
 ),

Image(image: CachedNetworkImageProvider(url))

您应该添加到pubspec文件

cached_network_image: <actual version here>

进入依赖项部分

答案 1 :(得分:6)

您可以使用 loadingBuilder ,这是flutter内置的Image.Network功能

Image.network(imgURL,fit: BoxFit.fill,
  loadingBuilder:(BuildContext context, Widget child,ImageChunkEvent loadingProgress) {
  if (loadingProgress == null) return child;
    return Center(
      child: CircularProgressIndicator(
      value: loadingProgress.expectedTotalBytes != null ? 
             loadingProgress.cumulativeBytesLoaded / loadingProgress.expectedTotalBytes
             : null,
      ),
    );
  },
),

答案 2 :(得分:0)

您也可以使用FadeInImage https://flutter.dev/docs/cookbook/images/fading-in-images

const transporter = nodemailer.createTransport({
            service: 'gmail',
            auth: {
                user: 'example@gmail.com',
                pass: 'dqsdsqdqsdsq'
            }
        });
        const filePath = path.join(__dirname, 'functions/src/Email/template.html');
        const source = fs.readFileSync(filePath, 'utf-8').toString();
        const template = handlebars.compile(source);
        const replacements = {
            schoolName: schoolName,
            className: className,
            date: new Date(),
            responsibiltyId: responsibiltyId,
            memorialId: memorialId
        };
        const htmlToSend = template(replacements);
        const mailOptions = {
            from: 'ADMIN <example@gmail.com>', // Something like: Jane Doe <janedoe@gmail.com>
            to: destination,
            subject: `Session Codes for Class ${className} | ${schoolName} | ${new Date()}`, // email subject
            html: htmlToSend
        };
        return transporter.sendMail(mailOptions, (error, info) => {
            if (error) {
                return handleError(res, error);
            }
            return res.status(200).json({
                timestamp: new Date(),
                status: 200,
                message: `Email has been sent successfuly to ${destination}`,
                extra: ''
            });
        });
    

答案 3 :(得分:0)

如果您想要图像为圆形。您可以以这种方式使用Circle Avatar,使其同时充当加载程序和显示程序...。

父圆头像会带有加载程序,如果我们在子圆头像上放置透明颜色,它将显示加载状态,直到加载完毕...

这种方法的优点是,您可以通过设置父圆头像的背景颜色并稍微增加其半径来简单地给边框

CircleAvatar(
                backgroundColor: Colors.red,
                radius: 65,
                backgroundImage: AssetImage('assets/bottombar/loading.gif'),
                child: CircleAvatar(
                  radius: 65,
                  backgroundColor: Colors.transparent,
                  backgroundImage: NetworkImage(_url),
                ),
              ),

答案 4 :(得分:0)

在尝试从 Internet 加载图像时,处理与缺少 Internet 等相关的错误是一种很好的做法。如果你使用 Image.network()

,ErrorBuilder 真的很好
Image.network(
      'https://example.does.not.exist/image.jpg',
      errorBuilder: (BuildContext context, Object exception, StackTrace stackTrace) {
        // Appropriate logging or analytics, e.g.
        // myAnalytics.recordError(
        //   'An error occurred loading "https://example.does.not.exist/image.jpg"',
        //   exception,
        //   stackTrace,
        // );
        return Text('?');
      },
    ),