如何在Flutter中将图像拉伸以适应整个背景(100%高度x100%宽度)?

137
我有一张图片,它的长宽比与设备屏幕不匹配。我想要拉伸这张图片,使其完全填满屏幕,并且不裁剪任何部分。
CSS 有百分比的概念,所以我可以将高度和宽度设置为100%。但是 Flutter 似乎没有这个概念,而且硬编码高度和宽度是不好的,所以我陷入了困境。
这是我的代码(我正在使用 Stack,因为我在图片前景中有其他内容):
Widget background = new Container(
  height: // Not sure what to put here!
  width: // Not sure what to put here!
  child: new Image.asset(
    asset.background,
    fit: BoxFit.fill, // I thought this would fill up my Container but it doesn't
  ),
);

return new Stack(
  children: <Widget>[
    background,
    foreground,
  ],
);
19个回答

172

要使图像填满其父元素,只需将其包装在FittedBox中:

FittedBox(
  child: Image.asset('foo.png'),
  fit: BoxFit.fill,
)

FittedBox会拉伸图像以填充空间。(请注意,此功能过去由BoxFit.fill提供,但API已更改,因此BoxFit不再提供此功能。 FittedBox应该可以作为替代品使用,不需要更改构造函数参数。)


另外,对于复杂的装饰,您可以使用Container而不是Image--并使用decoration/foregroundDecoration字段。

要使Container适合其父级,它应该是以下两者之一:

  • 没有子元素
  • alignment属性不为null

这里有一个示例,将两个图像和文本组合成单个Container,同时占用其父级的100%宽度/高度:

enter image description here

Container(
  foregroundDecoration: const BoxDecoration(
    image: DecorationImage(
        image: NetworkImage(
            'https://p6.storage.canalblog.com/69/50/922142/85510911_o.png'),
        fit: BoxFit.fill),
  ),
  decoration: const BoxDecoration(
    image: DecorationImage(
        alignment: Alignment(-.2, 0),
        image: NetworkImage(
            'http://www.naturerights.com/blog/wp-content/uploads/2017/12/Taranaki-NR-post-1170x550.png'),
        fit: BoxFit.cover),
  ),
  alignment: Alignment.bottomCenter,
  padding: EdgeInsets.only(bottom: 20),
  child: Text(
    "Hello World",
    style: Theme.of(context)
        .textTheme
        .display1
        .copyWith(color: Colors.white),
  ),
),

我怎样在这里添加一个淡入图像小部件?我认为我们不能。 - nick.tdr
4
Ty,我有更新的版本,我使用了以下代码:SizedBox.expand(child: Image.asset("assets/bg.png", fit: BoxFit.fill)) - Ido
那么为什么各种图像构造函数中仍然存在“fit”参数?如果它已被FittedBox实际替代,那还有什么用处呢? - Wecherowski
对我来说,使用FittedBox没有效果。但是@Ido的评论建议使用SizedBox.expand()对我有效。谢谢。 - Alex Roy

130

以下内容将使图像适应容器宽度的100%,而高度保持不变。 对于本地资源,请使用AssetImage

Container(
  width: MediaQuery.of(context).size.width,
  height: 100,
  decoration: BoxDecoration(
    image: DecorationImage(
      fit: BoxFit.fill,
      image: NetworkImage("https://picsum.photos/250?image=9"),
    ),
  ),
)

图像填充模式:

  • 填充 - 图像被拉伸

  • fit: BoxFit.fill
    

    enter image description here


  • 适合高度 - 图像保持比例,同时确保图像的整个高度显示(可能会溢出)

    fit: BoxFit.fitHeight
    

    enter image description here


  • 适应宽度 - 图像保持比例,同时确保显示图像的全宽度(可能溢出)

  • fit: BoxFit.fitWidth
    

    enter image description here


  • 覆盖 - 图片保持比例,确保最大程度地覆盖容器(可能会溢出)

  • fit: BoxFit.cover
    

    enter image description here


  • 包含 - 图片尽可能保持比例,尽可能小,如果需要显示整张图片则会缩小它的尺寸。

  • fit: BoxFit.contain
    

    输入图像描述


9
不要使用MediaQuery来使部件填充其父级。这不是你想要的。 - Rémi Rousselet
1
@RémiRousselet,你能解释一下这个原因吗(或者给我一个关于这个原因的链接)。谢谢。 - dilshan
我会选择“fit: BoxFit.cover,”。谢谢。 - Kamlesh
这个值得额外点赞,因为每个fit模式都有很棒的示例。 - Turkey

67

在您的 Stack 中,您应该将 background 小部件包装在一个 Positioned.fill 中。

return new Stack(
  children: <Widget>[
    new Positioned.fill(
      child: background,
    ),
    foreground,
  ],
);

感谢这个 Stack 小部件叠加,我一直在寻找这个小部件在 Flutter 中的应用。使用它,我可以在图像上方显示容器,太棒了! - ArifMustafa

45

对我来说,进行Web开发时,以下方式效果良好:

Image(
  image: AssetImage('lib/images/portadaSchamann5.png'),
  alignment: Alignment.center,
  height: double.infinity,
  width: double.infinity,
  fit: BoxFit.fill,
),

1
这似乎也是惯例:SizedBox.expand 也使用 double.infinity 作为其值。 - ted

18

也许不完全符合原帖的需求,但这是我在寻找解决方法时发现的页面,因此分享给所有遇到类似问题的人 :)

对于我的需求,Stack的fit属性解决了问题。否则,在(我的情况下)OctoImage中的图像被填充,并且提供其他Image.fit值没有任何效果。

Stack(
  fit: StackFit.expand, 
  children: [
    Image(
      image: provider,
      fit: BoxFit.cover,
    ),
    // other irrelevent children here
  ]
);

12

您的问题包含第一步,但需要宽度和高度。您可以获取屏幕的宽度和高度。这里进行了小修改。

//gets the screen width and height
double Width = MediaQuery.of(context).size.width;
double Height = MediaQuery.of(context).size.height;

Widget background = new Image.asset(
  asset.background,
  fit: BoxFit.fill,
  width: Width,
  height: Height,
);

return new Stack(
  children: <Widget>[
    background,
    foreground,
  ],
);

您还可以使用“宽度”和“高度”根据屏幕大小调整其他对象的尺寸。

例如:width: Height/2, height: Height/2 //使用相同的“高度”保持纵横比


2
fit: BoxFit.fill, 在图像上真是救命稻草,谢谢 :) - STEEL

8
使用BoxDecoration和DecorationImage可以实现此功能。以下是在此页面上找到的最佳示例:https://flutterbeads.com/set-background-image-in-flutter/
Container(
  constraints: BoxConstraints.expand(),
  decoration: const BoxDecoration(
    image: DecorationImage(
        image: AssetImage("assets/images/cat2.jpg"), 
        fit: BoxFit.cover),
  )

谢谢,谢谢,谢谢,谢谢。我真的在这个问题上苦思冥想。 - Debasis Sil

6

我认为对于你的目的,Flex比Container()更适合:

new Flex(
    direction: Axis.vertical,
    children: <Widget>[
      Image.asset(asset.background)
    ],
   )

你刚刚救了我的命 - :) 对我来说太完美了。 - iPatel

5

这应该可以正常工作,

Image.asset('assets/bg.jpg',fit: BoxFit.cover,),

这个。你还可以使用BoxFit.fitWidth、fitHeight和其他选项。 - George

4

以上答案均未对我起作用。由于没有被接受的答案,我发现以下方法将我的图像从水平边扩展到水平边:

Container ( width: MediaQuery
                    .of(context)
                    .size
                    .width,
                child: 
                  Image.network(my_image_name, fit: BoxFit.fitWidth )
              )

这个答案适用于你只想将图像适应整个宽度而不拉伸它的情况。 - Saurav Panda

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