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

zy1mlcev  于 2023-02-25  发布在  Flutter
关注(0)|答案(6)|浏览(124)

我尝试从网络加载图像并在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,
          ),
        );
      }),
    );
  }
}
ars1skjm

ars1skjm1#

您可以使用loadingBuilder,这是flutter for Image的内置功能。网络

Image.network(
                  widget.networkUrl,
                  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,
                      ),
                    );
                  },
                ),
rkkpypqq

rkkpypqq2#

我建议您使用https://pub.dartlang.org/packages/cached_network_image
对我的案子很有效。
简单的代码示例来自他们的r

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

Image(image: CachedNetworkImageProvider(url))

您应该将添加到pubspec文件

cached_network_image: <actual version here>

到依赖项部分

kkbh8khc

kkbh8khc3#

如果你想要一个圆形的图像。你可以使用圆形头像在这样一种方式,它将作为加载器和显示器都...
父圈头像将有加载器,如果我们把透明色的子圈头像,它会显示加载,直到它被加载...
这种方式的优点是你可以简单地设置父圈头像的背景色并稍微增加它的半径来给边框。

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

i34xakig4#

也可以使用淡入图像https://flutter.dev/docs/cookbook/images/fading-in-images

FadeInImage.assetNetwork(
        placeholder: 'assets/loading.gif',
        image: 'https://picsum.photos/250?image=9',
      ),
ubby3x7f

ubby3x7f5#

当试图从Internet加载图像时,处理与缺少Internet相关的错误是一个很好的做法。如果使用www.example.com(),ErrorBuilder非常好Image.network

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('😢');
      },
    ),
xurqigkl

xurqigkl6#

处理网络映像的最佳方式

在flutter中从网络加载图像的最好方法是使用flutter的 * 内置 * 网络功能并 * 根据您的要求进行定制 *,我不推荐/更喜欢使用任何类似CachedNetworkImage的软件包,因为它有时会在移动的上工作,并在网络上给予意外错误。
您可以按如下方式管理网络映像

Image.network(
        netWorkImageURL,
        fit: BoxFit.fill,
        // When image is loading from the server it takes some time
        // So we will show progress indicator while loading
        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,
            ),
          );
        },
        // When dealing with networks it completes with two states, 
        // complete with a value or completed with an error, 
        // So handling errors is very important otherwise it will crash the app screen. 
        // I showed dummy images from assets when there is an error, you can show some texts or anything you want.
        errorBuilder: (context, exception, stackTrace) {
          return Image.asset(
            AppAssets.dummyPostImg,
            fit: BoxFit.cover,
            height: (widget.hideBelowImage == null ||
                    widget.hideBelowImage == false)
                ? 170.h
                : 130.h,
            width: double.infinity,
          );
        },
      ),

相关问题