在Flutter中创建圆角缓存图像

63

我想创建一个圆形图像,在其中图像从网络获取并在Flutter中进行缓存。

这是我找到的一段代码,用于从网络获取圆形图像,但不进行缓存。

new Container(
    width:80.0,
    height: 80.0,
    decoration: new BoxDecoration(
    shape: BoxShape.circle,
        image: new DecorationImage(
            image: new NetworkImage('https://pbs.twimg.com/profile_images/945853318273761280/0U40alJG_400x400.jpg'),
        ),
    ),
),

现在我找到了一个小部件,可以从网络中获取、缓存和呈现图像

new CachedNetworkImage(imageUrl: 'https://pbs.twimg.com/profile_images/945853318273761280/0U40alJG_400x400.jpg')

但是当我把NetworkImage小部件替换成这个CachedNetworkImage时,它会给我一个错误,说NetworkImage不是image类型。

我怎样才能实现一个可以缓存的圆形图像?

编辑:根据答案建议,我尝试了这个,但仍然得到相同的错误:参数类型'CachedNetworkImage'不能分配给参数类型'DecorationImage'。

              decoration: new BoxDecoration(
                shape: BoxShape.circle,
                image: new CachedNetworkImage(image: 
                      'https://pbs.twimg.com/profile_images/945853318273761280/0U40alJG_400x400.jpg'),
              ),
7个回答

114

CachedNetworkImage有一个构建器(ImageWidgetBuilder),可进一步自定义图像的显示方式。 尝试以下方法:

CachedNetworkImage(
  imageUrl: 'https://pbs.twimg.com/profile_images/945853318273761280/0U40alJG_400x400.jpg',
  imageBuilder: (context, imageProvider) => Container(
    width: 80.0,
    height: 80.0,
    decoration: BoxDecoration(
      shape: BoxShape.circle,
      image: DecorationImage(
        image: imageProvider, fit: BoxFit.cover),
    ),
  ),
  placeholder: (context, url) => CircularProgressIndicator(),
  errorWidget: (context, url, error) => Icon(Icons.error),
),

placeholdererrorWidget是小部件,这意味着您可以将任何小部件放入其中并按照您的意愿进行自定义。


1
此解决方案仅适用于正方形图片,否则CircularProgressIndicator将与图片具有相同的比例。 - Paul
错误小部件将不会被圈出。 - Roman Soviak

38

DecorationImage接受ImageProvider而不是widget

解决此问题有两种方法:

cached_image_network提供了一个class,它extends ImageProvider,即CachedNetworkImageProvider

Container(
  width: 80.0,
  height: 80.0,
  decoration: BoxDecoration(
    shape: BoxShape.circle,
    image: DecorationImage(
      image: CachedNetworkImageProvider('https://pbs.twimg.com/profile_images/945853318273761280/0U40alJG_400x400.jpg'),
    ),
  ),
)

您也可以省略DecorationImage小部件,因为BoxDecoration将适用于任何小部件:

Container(
  width: 80.0,
  height: 80.0,
  decoration: BoxDecoration(
    shape: BoxShape.circle,
  ),
  child: CachedNetworkImage('https://pbs.twimg.com/profile_images/945853318273761280/0U40alJG_400x400.jpg'),
)

在后面的例子中,我使用常规的CachedNetworkImage,它将返回一个widget。

谢谢您的回答!我尝试了您提供的两个答案;第一个可以工作,但后面的例子无法工作...仍然出现相同的错误:参数类型“CachedNetworkImage”无法分配给参数类型“DecorationImage”。 - dshukertjr
@creativecreatormaybenot 我确实按照你告诉我的方法进行复制,就像编辑中一样,但仍然无法工作。 - dshukertjr
@dshukertjr 是的,我搞砸了。你需要将CachedNetworkImage作为Containerchild传递进去。我在答案中更新了这个。 - creativecreatorormaybenot
@creativecreatormaybenot 谢谢!现在一切都正常工作了! - dshukertjr
@dshukertjr 这个例子中我们可以使用LRU缓存吗? - Ravindra Bhanderi
2
这在矩形图像上不起作用,即使使用 fit: BoxFit.cover 也是如此。 - aytunch

27

ClipOval widget 用于将子widget 裁剪成圆形。

ClipOval(
  child: CachedNetworkImage(imageUrl: "https://pbs.twimg.com/profile_images/945853318273761280/0U40alJG_400x400.jpg",
   width: 80.0,
   height: 80.0,
  ),
)

1
不要使用 ClipRRect(它基本上用于圆角矩形),你应该使用 ClipOval。 - Udit
即使使用 fit: BoxFit.cover,这也无法处理矩形图像。 - aytunch
@aytunch 如果您能在Stack Overflow上发布您的代码,我会很高兴看到它。 - dshukertjr
4
这怎么可能成为被接受的答案!ClipOval看起来并不像一个完美的圆形! - Samer
尝试过这个,它最初从URL获取时显示正方形图像,然后变成圆形(如果宽度和高度相同),从UI角度来看,这看起来真的很糟糕。 - VipiN Negi
显示剩余5条评论

12
CircleAvatarCachedNetworkImageProvider的组合可以解决你的问题。以下是一个示例:
CircleAvatar(
  backgroundImage: CachedNetworkImageProvider(
  'https://pbs.twimg.com/profile_images/945853318273761280/0U40alJG_400x400.jpg',
  ),
),

7

在我的情况下,这节省了我的时间,也许对你也有用。

CachedNetworkImage(
  imageUrl: url,
  errorWidget: (context, url, error) => Text("error"),
  imageBuilder: (context, imageProvider) => CircleAvatar(
    radius: 50,
    backgroundImage: imageProvider,
   ),
  );

2

任意维度的通用解决方案

一种适用于任何尺寸和圆角的图片解决方案:

Container(
   width: 100,
   height: 125,
   decoration: BoxDecoration(
      borderRadius: BorderRadius.circular(34.0),
      color: Colors.grey,
   ),
   child: ClipRRect(
      borderRadius: BorderRadius.circular(34.0),
      child: CachedNetworkImage(
         imageUrl: "url",
         fit: BoxFit.cover,
         placeholder: (context, url) => Center(
            child: SizedBox(
               width: 40.0,
               height: 40.0,
               child: new CircularProgressIndicator(),
            ),
         ),
         errorWidget: (context, url, error) => new Icon(Icons.error),
      ),
   ),
),

这是完美的答案。解决了所有问题。 - rranj

0

通过使用ContainerClipRRect来实现,下面是一个例子:

Container(
  width: 160,
  height: 160,
    child: ClipRRect(
      borderRadius: BorderRadius.circular(80),
      child: CachedNetworkImage(
        fit: BoxFit.cover,
        imageUrl: '[YOUR URL]',
        errorWidget: (
          context,
          url,
          error,
        ) =>
          const Icon(Icons.error),
        progressIndicatorBuilder: (
          context,
          url,
          downloadProgress,
        ) =>
          Center(
            child: CircularProgressIndicator(
              value: downloadProgress.progress),
            ),
          )
      ),
    ),

Container组件的widthheight很重要,而且两者应该相等。

希望对其他人有所帮助;-)


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接