Flutter组件学习(二)—— Image

序言

上一节中,我们讲了 FlutterText 组件的一些用法以及 API,本节我们继续学习 Flutter 中的 Image 组件,同样先上图:

image

Image组件的构造方法

Android 中,我们都知道,图片的显示方式有很多,资源图片、网络图片、文件图片等等,在 Flutter 中也有多种方式,用来加载不同形式的图片:

  • Image:通过ImageProvider来加载图片
  • Image.asset:用来加载本地资源图片
  • Image.file:用来加载本地(File文件)图片
  • Image.network:用来加载网络图片
  • Image.memory:用来加载Uint8List资源(byte数组)图片
1、Image

Image 的一个参数是 ImageProvider,基本上所有形式的图片加载都是依赖它,这个类里面就是实现图片加载的原理。用法如下:

1new Image(image: new AssetImage('images/logo.png'));
2
3new Image(image: new NetworkImage('http://n.sinaimg.cn/sports/2_img/upload/cf0d0fdd/107/w1024h683/20181128/pKtl-hphsupx4744393.jpg'))
2、Image.asset

加载一个本地资源图片,和 Android 一样,有多种分辨率的图片可供选择,但是沿袭的是 iOS 的图片风格,分为 1x2x3x,具体做法是在项目的根目录下创建两个文件夹,如下图所示:

image

然后需要在 pubspec.yaml 文件中声明一下:

 1flutter:
 2
 3  # The following line ensures that the Material Icons font is
 4  # included with your application, so that you can use the icons in
 5  # the material Icons class.
 6  uses-material-design: true
 7  assets:
 8    - images/logo.png
 9    - images/2.0x/logo.png
10    - images/3.0x/logo.png

用法如下:

1new Image.asset('images/logo.png')
3、Image.file

加载一个本地 File 图片,比如相册中的图片,用法如下

1new Image.file(new File('/storage/xxx/xxx/test.jpg'))
4、Image.network

加载一个网络图片,用法如下:

1new Image.network('http://n.sinaimg.cn/sports/2_img/upload/cf0d0fdd/107/w1024h683/20181128/pKtl-hphsupx4744393.jpg')

有的时候我们需要像Android那样使用一个占位图或者图片加载出错时显示某张特定的图片,这时候需要用到 FadeInImage 这个组件:

 1new FadeInImage.assetNetwork(
 2  placeholder: 'images/logo.png',
 3  image: imageUrl,
 4  width: 120,
 5  fit: BoxFit.fitWidth,
 6)
 7
 8new FadeInImage.memoryNetwork(
 9  placeholder: kTransparentImage,
10  image: imageUrl,
11  width: 120,
12  fit: BoxFit.fitWidth,
13)

第一种方法是加载一个本地的占位图,第二种是加载一个透明的占位图,但是需要注意的是,这个组件是不可以设置加载出错显示的图片的;这里有另一种方法可以使用第三方 packageCachedNetworkImage 组件:

1new CachedNetworkImage(
2  width: 120,
3  fit: BoxFit.fitWidth,
4  placeholder: new CircularProgressIndicator(),
5  imageUrl: imageUrl,
6  errorWidget: new Icon(Icons.error),
7)

CachedNetworkImage 组件中的占位图是一个 Widget,这样的话就可以自定义了,你想使用什么样的组件进行占位都行,同样加载出错的占位图也是一个组件,也可以自己定义;该组件也是通过缓存来加载图片的。

5、Image.memory

用来将一个 byte 数组加载成图片,用法如下:

1new Image.memory(bytes)

Text组件的API

API名称

功能

width & height

用来指定显示图片区域的宽高(并非图片的宽高)

fit

设置图片填充,类似于Android中的ScaleType

color & colorBlendMode

这两个属性需要配合使用,就是颜色和图片混合,就类似于Android中的Xfermode

alignment

用来控制图片摆放的位置

repeat

用来设置图片重复显示(repeat-x水平重复,repeat-y垂直重复,repeat两个方向都重复,no-repeat默认情况不重复)

centerSlice

设置图片内部拉伸,相当于在图片内部设置了一个.9图,但是需要注意的是,要在显示图片的大小大于原图的情况下才可以使用这个属性,要不然会报错

matchTextDirection

这个需要配合Directionality进行使用

gaplessPlayback

当图片发生改变之后,重新加载图片过程中的样式(1、原图片保留)

fit 属性中有很多值可以设置:

属性名称

样式

BoxFit.contain

全图居中显示但不充满,显示原比例

BoxFit.cover

图片可能拉伸,也可能裁剪,但是充满容器

BoxFit.fill

全图显示且填充满,图片可能会拉伸

BoxFit.fitHeight

图片可能拉伸,可能裁剪,高度充满

BoxFit.fitWidth

图片可能拉伸,可能裁剪,宽度充满

BoxFit.scaleDown

效果和contain差不多, 但是只能缩小图片,不能放大图片

colorBlendMode 属性中有很多值可以设置,由于可选值太多,这里就不一一介绍了,有兴趣的可以去官网colorBlendMode属性介绍:https://docs.flutter.io/flutter/dart-ui/BlendMode-class.html看看

实现圆角/圆形图片

1、圆角

很多时候我们需要给图片设置圆角,那么在flutter中是怎么实现的呢?有很多种方法可以实现,下面我举两个例子:

 1使用裁剪来实现图片圆角:
 2
 3new ClipRRect(
 4  child: Image.network(
 5    imageUrl,
 6    scale: 8.5,
 7    fit: BoxFit.cover,
 8  ),
 9  borderRadius: BorderRadius.only(
10    topLeft: Radius.circular(20),
11    topRight: Radius.circular(20),
12  ),
13)
14
15使用边框来实现图片圆角:
16
17new Container(
18  width: 120,
19  height: 60,
20  decoration: BoxDecoration(
21    shape: BoxShape.rectangle,
22    borderRadius: BorderRadius.circular(10.0),
23    image: DecorationImage(
24        image: NetworkImage(imageUrl),
25        fit: BoxFit.cover),
26  ),
27)

需要注意的是,使用边框实现的时候要注意设置 fit 属性,不然效果也是有问题的,当然了你还可以使用 Material 组件来实现,这个大家可以自己去尝试。

2、圆形

圆形图片用得最多的应该是头像之类的,这种同样有多种方式可以实现,下面我也举两个例子:

 1使用裁剪实现圆形图片:
 2
 3new ClipOval(
 4    child: Image.network(
 5    imageUrl,
 6    scale: 8.5,
 7  ),
 8)
 9
10使用CircleAvatar来实现圆形图片:
11
12new CircleAvatar(
13  backgroundImage: NetworkImage(imageUrl),
14  radius: 50.0,
15)

当然了,你还可以使用边框 BoxDecoration 来实现,效果也是一样的。

下面来看一下详细的代码实现:

  1class _ImageViewWidget extends State<ImageViewWidget> {
  2  var imageUrl =
  3      "http://n.sinaimg.cn/sports/2_img/upload/cf0d0fdd/107/w1024h683/20181128/pKtl-hphsupx4744393.jpg";
  4
  5  var imageUrl2 =
  6      "http://n.sinaimg.cn/sports/2_img/upload/4f160954/107/w1024h683/20181128/Yrxn-hpinrya6814381.jpg";
  7
  8  @override
  9  Widget build(BuildContext context) {
 10    return new Align(
 11      child: ListView(
 12        children: <Widget>[
 13          new Text('资源图片:'),
 14          new Row(
 15            mainAxisAlignment: MainAxisAlignment.center,
 16            children: <Widget>[
 17              new Padding(
 18                padding: const EdgeInsets.all(10.0),
 19                child: Image.asset(
 20                  'images/logo.png',
 21                ),
 22              ),
 23//              new Image.file(
 24//                File('/storage/emulated/0/Download/test.jpg'),
 25//                width: 120,
 26//                //fill(全图显示且填充满,图片可能会拉伸),contain(全图显示但不充满,显示原比例),cover(显示可能拉伸,也可能裁剪,充满)
 27//                //fitWidth(显示可能拉伸,可能裁剪,宽度充满),fitHeight显示可能拉伸,可能裁剪,高度充满),scaleDown(效果和contain差不多,但是)
 28//              ),
 29            ],
 30          ),
 31          new Text('网络占位图片CachedNetworkImage:'),
 32          new Padding(
 33            padding: const EdgeInsets.fromLTRB(0.0, 10.0, 0.0, 10.0),
 34            child: Row(
 35              mainAxisAlignment: MainAxisAlignment.center,
 36              children: <Widget>[
 37                Image.network(
 38                  imageUrl,
 39                  scale: 8.5,
 40                ),
 41                new Padding(
 42                  padding: const EdgeInsets.fromLTRB(10.0, 0.0, 10.0, 0.0),
 43                  child: CachedNetworkImage(
 44                    width: 120,
 45                    fit: BoxFit.fitWidth,
 46                    placeholder: Image(image: AssetImage('images/logo.png')),
 47                    imageUrl: imageUrl,
 48                    errorWidget: new Icon(Icons.error),
 49                  ),
 50                ),
 51                new CachedNetworkImage(
 52                  imageUrl: imageUrl,
 53                  width: 120,
 54                  fit: BoxFit.fitWidth,
 55                  placeholder: CircularProgressIndicator(),
 56                  errorWidget: new Icon(Icons.error),
 57                )
 58              ],
 59            ),
 60          ),
 61          new Text('网络占位图片FadeInImage:'),
 62          new Padding(
 63            padding: const EdgeInsets.fromLTRB(0.0, 10.0, 0.0, 10.0),
 64            child: new Row(
 65              children: <Widget>[
 66                new FadeInImage.memoryNetwork(
 67                  placeholder: kTransparentImage,
 68                  image: imageUrl,
 69                  width: 120,
 70                  fit: BoxFit.fitWidth,
 71                ),
 72                new Padding(
 73                  padding: const EdgeInsets.fromLTRB(10.0, 0.0, 10.0, 0.0),
 74                  child: new FadeInImage.assetNetwork(
 75                    placeholder: 'images/logo.png',
 76                    image: imageUrl,
 77                    width: 120,
 78                    fit: BoxFit.fitWidth,
 79                  ),
 80                ),
 81              ],
 82              mainAxisAlignment: MainAxisAlignment.center,
 83            ),
 84          ),
 85          new Text('圆形圆角图片:'),
 86          new Padding(
 87            padding: const EdgeInsets.fromLTRB(0.0, 10.0, 0.0, 10.0),
 88            child: Row(
 89              mainAxisAlignment: MainAxisAlignment.center,
 90              children: <Widget>[
 91                new ClipOval(
 92                  child: Image.network(
 93                    imageUrl,
 94                    width: 100,
 95                    height: 100,
 96                    fit: BoxFit.fitHeight,
 97                  ),
 98                ),
 99                new Padding(
100                  padding: const EdgeInsets.fromLTRB(10.0, 0.0, 10.0, 0.0),
101                  child: ClipOval(
102                    child: Image.asset(
103                      'images/logo.png',
104                      width: 100,
105                      height: 100,
106                      fit: BoxFit.fitHeight,
107                    ),
108                  ),
109                ),
110                new ClipRRect(
111                  child: Image.network(
112                    imageUrl,
113                    scale: 8.5,
114                    fit: BoxFit.cover,
115                  ),
116                  borderRadius: BorderRadius.only(
117                    topLeft: Radius.circular(20),
118                    topRight: Radius.circular(20),
119                  ),
120                )
121              ],
122            ),
123          ),
124          new Text('颜色混合图片:'),
125          new Padding(
126            padding: const EdgeInsets.fromLTRB(0.0, 10.0, 0.0, 10.0),
127            child: Row(
128              mainAxisAlignment: MainAxisAlignment.center,
129              children: <Widget>[
130                new Image.asset(
131                  'images/logo.png',
132                  color: Colors.red,
133                  colorBlendMode: BlendMode.darken,
134                ),
135                new Padding(
136                  padding: const EdgeInsets.fromLTRB(10.0, 0.0, 10.0, 0.0),
137                  child: Image.network(
138                    imageUrl,
139                    scale: 8.5,
140                    colorBlendMode: BlendMode.colorDodge,
141                    color: Colors.blue,
142                  ),
143                ),
144              ],
145            ),
146          ),
147          new Text('centerSlice图片内部拉伸:'),
148          new Padding(
149            padding: const EdgeInsets.fromLTRB(0.0, 10.0, 0.0, 10.0),
150            child: new Image.asset(
151              'images/logo.png',
152              width: 250,
153              height: 250,
154              fit: BoxFit.contain,
155              centerSlice:
156                  new Rect.fromCircle(center: const Offset(20, 20), radius: 1),
157            ),
158          ),
159          new Text('matchTextDirection图片内部方向'),
160          new Padding(
161            padding: const EdgeInsets.fromLTRB(0.0, 10.0, 0.0, 10.0),
162            child: Row(
163              mainAxisAlignment: MainAxisAlignment.center,
164              children: <Widget>[
165                new Directionality(
166                  textDirection: TextDirection.ltr,
167                  child: Image.network(
168                    imageUrl,
169                    height: 100,
170                    matchTextDirection: true,
171                    fit: BoxFit.fitHeight,
172                  ),
173                ),
174                new Padding(
175                  padding: const EdgeInsets.fromLTRB(10.0, 0.0, 10.0, 0.0),
176                  child: Directionality(
177                    textDirection: TextDirection.rtl,
178                    child: Image.network(
179                      imageUrl,
180                      height: 100,
181                      matchTextDirection: true,
182                      fit: BoxFit.fitHeight,
183                    ),
184                  ),
185                ),
186              ],
187            ),
188          ),
189          new Text('点击替换图片'),
190          new Padding(
191            padding: const EdgeInsets.fromLTRB(0.0, 10.0, 0.0, 10.0),
192            child: Row(
193              children: <Widget>[
194                new RaisedButton(
195                  onPressed: () {
196                    setState(() {
197                      widget.networkImage =
198                          new NetworkImage(imageUrl2, scale: 8.5);
199                    });
200                  },
201                  child: Text('点击更换图片'),
202                ),
203                new Image(
204                  gaplessPlayback: false,
205                  fit: BoxFit.contain,
206                  image: widget.networkImage,
207                ),
208              ],
209            ),
210          )
211        ],
212      ),
213    );
214  }
215}

代码已上传至Github:https://github.com/24Kshign/FlutterWorkSpace/tree/master/flutter_element

原文发布于微信公众号 - IT先森养成记(cyg_24kshign)

原文发表时间:2018-12-03

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

扫码关注云+社区

领取腾讯云代金券