Image 图片作为日常中最常用的 Widget 却也是最容易忽略的,小菜在日常中通常仅用到 Image 展示图片属性,但是 Image 本身非常强大,有很多小菜所不熟知的属性特征;今天小菜重新认识一下 Image Widget;
Image
Image 作为支持展示多种图片格式的 Widget,提供了多种构造方法;
- Image() 用于从 ImageProvider 中获取图片资源;
- Image.asset() 用于从 AssetBundle 中获取工程目录图片资源;
- Image.network() 用于从 URL 中获取网络图片资源;
- Image.file() 用于从 File 中获取本地图片资源;
- Image.memory() 用于从 Uint8List 中获取内存图片资源;
源码分析
const Image({
Key key,
@required this.image, // 图片资源
this.frameBuilder, // 帧构造器
this.loadingBuilder, // 加载过程帧构造器
this.errorBuilder, // 失败状态帧构造器
this.semanticLabel,
this.excludeFromSemantics = false,
this.width, // 图片宽
this.height, // 图片高
this.color, // 图片颜色
this.colorBlendMode, // 混合方式
this.fit, // 分布效果
this.alignment = Alignment.center, // 对齐方式
this.repeat = ImageRepeat.noRepeat, // 平铺效果
this.centerSlice,
this.matchTextDirection = false,
this.gaplessPlayback = false,
this.isAntiAlias = false,
this.filterQuality = FilterQuality.low,
})
简单分析源码可得,Image 作为一个有状态的 StatefulWidget,主要通过 image 属性来设置图片资源,多种附加属性来支持图片更多样的展示效果;小菜逐一进行尝试学习;
案例尝试
1. image
Image 通过 ImageProvider 来展示图片,Flutter 提供了多种方式,与各类命名构造方法对应;
_imageWid00(isNet) => Image(
image: isNet
? NetworkImage('https://flutter.github.io/assets-for-api-docs/assets/widgets/owl.jpg')
: AssetImage('images/icon_hzw01.jpg'));
2. frameBuilder
typedef ImageFrameBuilder = Widget Function(
BuildContext context,
Widget child,
int frame,
bool wasSynchronouslyLoaded,
);
frameBuilder 帧构造器用于控制在 Image 构建时小部件签名,其中 child 用于保存默认 Image 图片并且不可为空;frame 为渲染 Image 帧数下标,默认为首帧;可以通过 frameBuilder 设置图片基本样式;
_imageWid01(isNet) {
return Image(
frameBuilder: (BuildContext context, Widget child, int frame, bool wasSynchronouslyLoaded) {
return Container(
padding: EdgeInsets.all(18.0),
color: Colors.deepOrange.withOpacity(0.4),
child: child);
},
image: isNet
? NetworkImage('https://flutter.github.io/assets-for-api-docs/assets/widgets/owl.jpg')
: AssetImage('images/icon_hzw01.jpg'));
}
3. loadingBuilder
loadingBuilder 加载状态帧构造器,在加载过程中展示的 Image 构造器;查看效果图可以看到,设置了两层内边距,因为在 loading 状态和加载完状态时都对 child 设置了内边距;
_imageWid02(isNet) {
return Image(
frameBuilder: (BuildContext context, Widget child, int frame, bool wasSynchronouslyLoaded) {
return Container(
padding: EdgeInsets.all(18.0),
color: Colors.deepOrange.withOpacity(0.4),
child: child);
},
loadingBuilder: (BuildContext context, Widget child, ImageChunkEvent loadingProgress) {
return Container(
padding: EdgeInsets.all(18.0),
color: Colors.green.withOpacity(0.4),
child: child);
},
image: isNet
? NetworkImage('https://flutter.github.io/assets-for-api-docs/assets/widgets/owl.jpg')
: AssetImage('images/icon_hzw01.jpg'));
}
4. errorBuilder
errorBuilder 为失败时替换 Image 展示的构造器;
_imageWid03(isNet) {
return Image(
frameBuilder: (BuildContext context, Widget child, int frame, bool wasSynchronouslyLoaded) {
return Container(
padding: EdgeInsets.all(18.0),
color: Colors.deepOrange.withOpacity(0.4),
child: child);
},
loadingBuilder: (BuildContext context, Widget child, ImageChunkEvent loadingProgress) {
return Container(
padding: EdgeInsets.all(18.0),
color: Colors.green.withOpacity(0.4),
child: child);
},
errorBuilder: (BuildContext context, Object exception, StackTrace stackTrace) {
return Container(
height: 100.0, padding: EdgeInsets.all(18.0),
color: Colors.grey.withOpacity(0.4),
child: Center(child: Icon(Icons.error)));
},
image: isNet
? NetworkImage('https://flutter.github.io/assets-for-api-docs/assets/widgets/owl11.jpg')
: AssetImage('images/icon_hzw0111.jpg'));
}
5. width & height
width & height 为设置图片展示宽高尺寸;
_imageWid05(width, height) => Image(image: AssetImage('images/icon_hzw01.jpg'), width: width, height: height);
6. color & colorBlendMode
color & colorBlendMode 配合使用绘制的混合模式,可以用来创建其他效果,如黑白模式,X 光特效等;之前小菜有所尝试;
_imageWid06(isNet, index) {
BlendMode blendMode;
if (index == 0) {
blendMode = BlendMode.difference;
} else if (index == 1) {
blendMode = BlendMode.screen;
} else if (index == 2) {
blendMode = BlendMode.hardLight;
} else {
blendMode = BlendMode.colorBurn;
}
return Image(
color: Colors.indigoAccent.withOpacity(0.4),
colorBlendMode: blendMode,
image: isNet
? NetworkImage('https://flutter.github.io/assets-for-api-docs/assets/widgets/owl.jpg')
: AssetImage('images/icon_hzw01.jpg'));
}
7. alignment
alignment 为边界内的对齐方式;当图片资源小于图片尺寸时,可以通过 Alignment 调整对齐方式;
_imageWid07(index) {
Alignment alignment;
if (index == 0) {
alignment = Alignment.topLeft;
} else if (index == 1) {
alignment = Alignment.center;
} else {
alignment = Alignment.bottomRight;
}
return Image(
image: AssetImage('images/icon_wechat_moments.png'),
alignment: alignment,
height: 120,
frameBuilder: (BuildContext context, Widget child, int frame, bool wasSynchronouslyLoaded) {
return Container(
padding: EdgeInsets.all(2.0),
color: Colors.deepOrange.withOpacity(0.4),
child: child);
});
}
8. repeat
repeat 为覆盖图片未覆盖区域样式,包括水平方向或竖直方向平铺效果;
_imageWid08(index) {
ImageRepeat repeat;
if (index == 0) {
repeat = ImageRepeat.repeatX;
} else if (index == 1) {
repeat = ImageRepeat.repeatY;
} else {
repeat = ImageRepeat.repeat;
}
return Image(
image: AssetImage('images/icon_wechat_moments.png'),
repeat: repeat, height: 120,
frameBuilder: (BuildContext context, Widget child, int frame, bool wasSynchronouslyLoaded) {
return Container(
padding: EdgeInsets.all(18.0),
color: Colors.deepOrange.withOpacity(0.4),
child: child);
});
}
9. fit
fit 为图片在布局中的分布效果;
- BoxFit.fitWidth:整体图片资源以图片宽度为基准放大或缩小;
- BoxFit.fitHeight:整体图片资源以图片高度为基准放大或缩小;
- BoxFit.fill:整体图片填充满图片宽高,可进行拉伸或压缩等;
- BoxFit.contain:整体图片按比例放大或缩小至最大宽或高可容纳范围,并在设置宽高内居中整体显示;
- BoxFit.cover:整体图片按比例放大或缩小至最小宽或高可容纳范围,并居中显示;
- BoxFit.scaleDown:整体图片大于设置尺寸,按比例缩小并居中显示;若整体图片小于设置尺寸,则不做处理,居中显示;
_imageWid09(index) {
BoxFit fit;
if (index == 0) {
fit = BoxFit.fitWidth;
} else if (index == 1) {
fit = BoxFit.fitHeight;
} else if (index == 2) {
fit = BoxFit.fill;
} else if (index == 3) {
fit = BoxFit.cover;
} else if (index == 4) {
fit = BoxFit.contain;
} else {
fit = BoxFit.scaleDown;
}
return Image(
image: AssetImage('images/icon_hzw03.jpg'),
fit: fit, height: 120,
frameBuilder: (BuildContext context, Widget child, int frame, bool wasSynchronouslyLoaded) {
return Container(
padding: EdgeInsets.all(2.0),
color: Colors.deepOrange.withOpacity(0.4),
child: child);
});
}
10. centerSlice
centerSlice 用于设置一个矩形,类似于 .9.png 图一样,进行固定范围的拉伸;其中注意 fit 类型不可为 BoxFit.none 或 BoxFit.cover;
_imageWid10(index) {
Rect rect;
if (index == 0) {
rect = null;
} else if (index == 1) {
rect = Rect.fromLTWH(100, 100, 50, 50);
} else if (index == 2) {
rect = Rect.fromLTWH(50, 50, 50, 50);
}
return Image(
fit: BoxFit.contain,
width: 250,
height: 250,
centerSlice: rect,
image: AssetImage('images/icon_music.png'));
}
小菜对 Image 的学习还仅限于基础应用,对于平时不常用的属性有了进一步了解,但对源码的学习还不够深入;如有错误,请多多指导!
来源: 阿策小和尚