123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274 |
- import 'dart:convert';
- import 'dart:io';
- import 'package:extended_image/extended_image.dart';
- import 'package:flutter/material.dart';
- import 'package:cs_resources/generated/assets.dart';
- import 'package:shared/utils/image_path_utils.dart';
- import 'package:shared/utils/reg_utils.dart';
- import 'package:shared/utils/util.dart';
- /*
- 图片加载(网络图片,Base64图片,File图片,Asset图片,支持圆角与边框,支持占位图)
- 尽可能少的嵌套布局,如果不支持部分属性则不会嵌套对应的Widget,由于图片与文本是最常用的控件,尽量减少嵌套层级提升性能
- */
- class MyLoadImage extends StatelessWidget {
- MyLoadImage(
- this.image, {
- Key? key,
- this.width,
- this.height,
- this.fit = BoxFit.cover,
- this.placeholderPath = '',
- this.cacheWidth,
- this.cacheHeight,
- this.isCircle,
- this.cornerRadius,
- this.borderColor,
- this.borderWidth,
- this.onClick,
- }) : super(key: key) {
- if (isCircle != null) {
- if (isCircle ?? true) {
- cornerRadius = width ?? 0 / 2;
- }
- }
- }
- final String? image;
- final double? width;
- final double? height;
- final BoxFit fit;
- final String placeholderPath;
- final int? cacheWidth;
- final int? cacheHeight;
- bool? isCircle = false;
- double? borderWidth = 0;
- Color? borderColor = Colors.transparent;
- VoidCallback? onClick;
- double? cornerRadius = 0;
- @override
- Widget build(BuildContext context) {
- //占位图
- final Widget placeholder = placeholderPath.isEmpty
- ? Container(
- //如果没有设置占位图,使用默认的灰色背景内置Icon小图标
- width: width,
- height: height,
- color:const Color(0xffE0E0E0),
- alignment: Alignment.center,
- child: const MyAssetImage(
- Assets.baseLibImageDefaultPlaceholder,
- width: 38,
- height: 32,
- ),
- )
- : MyAssetImage(
- //如果有占位图,展示自己的占位图
- placeholderPath,
- height: height,
- width: width,
- fit: fit,
- );
- if (Utils.isEmpty(image) || image!.startsWith('http') || image!.startsWith('data:')) {
- //加载网络图片
- return _buildDecorationNetImage(placeholder);
- } else if (Utils.isNotEmpty(image) && RegCheckUtils.isLocalImagePath(image!)) {
- //加载本地File路径的图片
- return _buildDecorationFileImage();
- } else {
- //加载本地资源的图片
- return _buildDecorationAssetImage();
- }
- }
- // ===================================== 网络图片与 Base64 图片 ↓ =====================================
- // 网络图片加载布局- 是否携带触摸事件与圆角
- Widget _buildDecorationNetImage(Widget placeholder) {
- if (cornerRadius != null && cornerRadius! > 0) {
- return Container(
- decoration: BoxDecoration(
- border: Border.all(width: borderWidth ?? 0, color: borderColor ?? Colors.transparent),
- borderRadius: BorderRadius.all(Radius.circular(cornerRadius ?? 0)),
- ),
- child: _buildGestureNetImg(placeholder),
- );
- } else {
- return _buildGestureNetImg(placeholder);
- }
- }
- // 网络图片加载布局- 是否携带触摸事件
- Widget _buildGestureNetImg(Widget placeholder) {
- return onClick != null
- ? GestureDetector(
- onTap: onClick,
- child: _buildClipImg(placeholder, placeholder),
- )
- : _buildClipImg(placeholder, placeholder);
- }
- /// 真正的网络图片布局 (ExtendedImage框架)
- ClipRRect _buildClipImg(Widget placeholderWidget, Widget errorWidget) {
- if (image?.startsWith('data:') == true) {
- return ClipRRect(
- borderRadius: BorderRadius.circular(cornerRadius ?? 0),
- //加载 Base64 图片
- child: Image.memory(
- base64.decode(image?.replaceFirst('data:image/png;base64,', '') ?? ''),
- width: width,
- height: height,
- fit: fit,
- ));
- } else if (image?.startsWith('http') == true) {
- return ClipRRect(
- borderRadius: BorderRadius.circular(cornerRadius ?? 0),
- //加载网络图片
- child: ExtendedImage.network(
- image ?? "",
- width: width,
- height: height,
- fit: fit,
- timeLimit: const Duration(milliseconds: 30000),
- cache: true,
- //是否启用缓存
- //状态监听
- loadStateChanged: (ExtendedImageState state) {
- switch (state.extendedImageLoadState) {
- case LoadState.loading:
- return placeholderWidget;
- case LoadState.completed:
- return null;
- case LoadState.failed:
- return errorWidget;
- }
- },
- ));
- } else {
- //由于这里只是加载Http图片与Base64图片,这里做一下兜底,异常的时候展示占位图背景
- return ClipRRect(
- borderRadius: BorderRadius.circular(cornerRadius ?? 0),
- child: placeholderWidget,
- );
- }
- }
- // ===================================== File 图片 ↓ =====================================
- // 文件加载 - 是否携带触摸事件与圆角
- Widget _buildDecorationFileImage() {
- if (cornerRadius != null && cornerRadius! > 0) {
- return Container(
- decoration: BoxDecoration(
- border: Border.all(width: borderWidth ?? 0, color: borderColor ?? Colors.transparent),
- borderRadius: BorderRadius.all(Radius.circular(cornerRadius ?? 0)),
- ),
- child: _buildGestureFileImage(),
- );
- } else {
- return _buildGestureFileImage();
- }
- }
- // 文件加载 - 是否携带触摸事件
- Widget _buildGestureFileImage() {
- return onClick != null
- ? GestureDetector(
- onTap: onClick,
- child: _buildFileImage(),
- )
- : _buildFileImage();
- }
- // 文件的加载
- Widget _buildFileImage() {
- return ClipRRect(
- borderRadius: BorderRadius.circular(cornerRadius ?? 0),
- child: Image.file(
- File(image!),
- height: height,
- width: width,
- cacheWidth: cacheWidth,
- cacheHeight: cacheHeight,
- fit: fit,
- excludeFromSemantics: true,
- ),
- );
- }
- // ===================================== Asset 图片 ↓ =====================================
- //带装饰的Asset图片资源
- Widget _buildDecorationAssetImage() {
- if (cornerRadius != null && cornerRadius! > 0) {
- return Container(
- decoration: BoxDecoration(
- border: Border.all(width: borderWidth ?? 0, color: borderColor ?? Colors.transparent),
- borderRadius: BorderRadius.all(Radius.circular(cornerRadius ?? 0)),
- ),
- child: _buildGestureAssetImage(),
- );
- } else {
- return _buildGestureAssetImage();
- }
- }
- //带手势的Asset图片资源
- Widget _buildGestureAssetImage() {
- return onClick != null
- ? GestureDetector(
- onTap: onClick,
- child: _buildAssetImg(),
- )
- : _buildAssetImg();
- }
- //真正的本地图片布局
- MyAssetImage _buildAssetImg() {
- return MyAssetImage(
- image ?? "",
- height: height,
- width: width,
- fit: fit,
- cacheWidth: cacheWidth,
- cacheHeight: cacheHeight,
- );
- }
- }
- /// 加载本地资源图片
- class MyAssetImage extends StatelessWidget {
- const MyAssetImage(this.image, {Key? key, this.width, this.height, this.cacheWidth, this.cacheHeight, this.fit, this.color}) : super(key: key);
- final String image;
- final double? width;
- final double? height;
- final int? cacheWidth;
- final int? cacheHeight;
- final BoxFit? fit;
- final Color? color;
- @override
- Widget build(BuildContext context) {
- var finalPath = ImagePathUtils.getImgPath(image);
- return Image.asset(
- finalPath,
- package: 'cs_resources',
- height: height,
- width: width,
- cacheWidth: cacheWidth,
- cacheHeight: cacheHeight,
- fit: fit,
- color: color,
- /// 忽略图片语义
- excludeFromSemantics: true,
- );
- }
- }
|