介绍
CircleAvatar组件增强版.头像组件,可以适配文字,图片以及图标。可以设置背景颜色为渐变不局限于圆形 可以增加阴影以及边框
根据官方圆形头像组件 修改 不局限于圆形可以变化任意形状 实现方式为AnimatedContainer的 foregroundDecoration
代码演示
基础用法
const HcAvatar(
radius:10.0,
size: 20.0,
backgroundImageUrl: 'assets/images/group.png',
child: Text("张三"),
),
渐变背景
HcAvatar支持传入Gradient来构建渐变背景
const HcAvatar(
radius:10.0,
size: 20.0,
gradient: LinearGradient(
colors: [Colors.blue, Colors.yellow],
stops: [0.1, 0.9],
transform: GradientRotation(pi / 2),
),
child: Text("张三"),
),
展示图标
child组件一般用来展示文字/icon 如果需要展示图片请用backgroundImageUrl/foregroundImageUrl
const HcAvatar(
radius:20.0,
size: 30.0,
child: Icon(Icons.icecream_outlined),
),
增加阴影
const HcAvatar(
radius: 20.0,
size: 40.0,
gradient: LinearGradient(
colors: [Colors.blue, Colors.yellow],
stops: [0.1, 0.9],
transform: GradientRotation(pi / 2),
),
boxShadow: [
BoxShadow(
color: Colors.amber,
offset: Offset(0, 10),
blurRadius: 10,
)
],
child: Icon(Icons.icecream_outlined),
),
增加边框
HcAvatar(
borderColor: Colors.purple,
borderWidth: 3,
foregroundImageUrl: 'assets/images/icon.jpeg',
),
修改大小
HcAvatar(
size: 20,
foregroundImageUrl: 'assets/images/icon.jpeg',
),
特殊用法
同时设置前景图和背景图 前景图报错展示背景图 背景图报错展示背景颜色
HcAvatar(
foregroundImageUrl: 'assets/images/i1con.jpeg',
backgroundImageUrl: 'assets/images/used.png',
),
只展示文字不展示图片
HcAvatar(
child: Text("张三"),
),
背景图片+文字
HcAvatar(
child: Text("张三"),
backgroundImageUrl: 'assets/images/icon.jpeg',
),
渐变背景+Icon
HcAvatar(
child: Icon(Icons.icecream_outlined),
gradient: HcGradientUtil.generateLinearGradient(
colors: [Colors.purple, Colors.black12]),
),
API
props
参数 | 说明 | 类型 | 默认值 | 是否必填 |
---|---|---|---|---|
size | 组件大小 | double | 40.0 | false |
radius | 头像圆角 | double | 20.0 | false |
backgroundColor | 图片背景纯色(优先级低于渐变) | color | - | false |
borderColor | 边框颜色 | color | - | false |
borderWidth | 边框宽度 | double | - | false |
gradient | 渐变背景(背景图显示出错时展示) | Gradient | - | false |
foregroundColor | 前景色 | color | - | false |
backgroundImageUrl | 背景图片地址(前景图片显示出错展示) | String | - | false |
foregroundImageUrl | 前景图片地址 | String | - | false |
onForegroundImageError | 前景图片显示出错的回调 | Function | - | false |
onBackgroundImageError | 背景图片出错的回调 | Function | - | false |
child | 背景色上显示的内容 | Widget | - | false |
boxShadow | 背景阴影 | List<BoxShadow> | - | false |
显示顺序
foregroundImageUrl>backgroundImageUrl>gradient>backgroundColor<p>
foregroundColor的作用是调节child的文字颜色
Function
方法名 | 说明 | 参数 | 返回类型 |
---|---|---|---|
onForegroundImageError/ onBackgroundImageError | 背景图片出错的回调 | Function(Object exception, StackTrace? stackTrace) | void |
项目源码
checkAndFixImagePath方法在Flutter 重复造轮子 (1) Image 图片显示组件的封装中有不在此赘述
/// 头像组件
class HcAvatar extends StatelessWidget {
//图片的大小
final double size;
//图标的圆角
final double radius;
//背景颜色
final Color? backgroundColor;
//边框颜色
final Color? borderColor;
//边框宽度
final double borderWidth;
//渐变色 渐变色颜色优先度大于Color
// foregroundImageUrl>backgroundImageUrl>gradient>backgroundColor
final Gradient? gradient;
//前景色
final Color? foregroundColor;
//图片背景Url
final String? backgroundImageUrl;
//图片前景Url
final String? foregroundImageUrl;
//出错的回调
final ImageErrorListener? onForegroundImageError;
//出错的回调
final ImageErrorListener? onBackgroundImageError;
//子组件
final Widget? child;
//阴影
final List<BoxShadow>? boxShadow;
const HcAvatar(
{Key? key,
this.size = HcSize.defaultAvatarSize,
this.radius = HcSize.defaultRadius,
this.backgroundColor,
this.foregroundColor,
this.boxShadow,
this.borderColor,
this.borderWidth = HcSize.defaultAvatarBorderWidth,
this.gradient,
this.child,
this.backgroundImageUrl,
this.foregroundImageUrl,
this.onForegroundImageError,
this.onBackgroundImageError})
: super(key: key);
@override
Widget build(BuildContext context) {
final ThemeData theme = Theme.of(context);
final Color? effectiveForegroundColor = foregroundColor ??
(theme.useMaterial3 ? theme.colorScheme.onPrimaryContainer : null);
final TextStyle effectiveTextStyle = theme.useMaterial3
? theme.textTheme.titleMedium!
: theme.primaryTextTheme.titleMedium!;
TextStyle textStyle =
effectiveTextStyle.copyWith(color: effectiveForegroundColor);
Color? effectiveBackgroundColor = backgroundColor ??
(theme.useMaterial3 ? theme.colorScheme.primaryContainer : null);
if (effectiveBackgroundColor == null) {
switch (ThemeData.estimateBrightnessForColor(textStyle.color!)) {
case Brightness.dark:
effectiveBackgroundColor = theme.primaryColorLight;
break;
case Brightness.light:
effectiveBackgroundColor = theme.primaryColorDark;
break;
}
} else if (effectiveForegroundColor == null) {
switch (ThemeData.estimateBrightnessForColor(backgroundColor!)) {
case Brightness.dark:
textStyle = textStyle.copyWith(color: theme.primaryColorLight);
break;
case Brightness.light:
textStyle = textStyle.copyWith(color: theme.primaryColorDark);
break;
}
}
return AnimatedContainer(
constraints: BoxConstraints(
minHeight: size,
minWidth: size,
maxWidth: size + borderWidth * 2,
maxHeight: size + borderWidth * 2,
),
duration: kThemeChangeDuration,
decoration: BoxDecoration(
boxShadow: boxShadow,
border: borderColor != null
? Border.all(color: borderColor!, width: borderWidth)
: null,
gradient: gradient,
borderRadius:
BorderRadius.circular((size + borderWidth * 2) / (size / radius)),
color: effectiveBackgroundColor,
image: backgroundImageUrl != null
? DecorationImage(
image: _buildImageProvider(backgroundImageUrl),
onError: onBackgroundImageError,
fit: BoxFit.cover,
)
: null,
),
foregroundDecoration: foregroundImageUrl != null
? BoxDecoration(
image: DecorationImage(
image: _buildImageProvider(foregroundImageUrl!),
onError: onForegroundImageError,
fit: BoxFit.cover,
),
// boxShadow: boxShadow,
borderRadius: BorderRadius.circular(
(size + borderWidth * 2) / (size / radius)),
)
: null,
child: child == null
? null
: Center(
child: MediaQuery(
// Need to ignore the ambient textScaleFactor here so that the
// text doesn't escape the avatar when the textScaleFactor is large.
data: MediaQuery.of(context).copyWith(textScaleFactor: 1.0),
child: IconTheme(
data: theme.iconTheme.copyWith(color: textStyle.color),
child: DefaultTextStyle(
style: textStyle,
child: child!,
),
),
),
),
);
}
ImageProvider _buildImageProvider(imagePath) {
Map<String, dynamic> imageInfo = HCFileUtil.checkAndFixImagePath(imagePath);
HcImageType type = imageInfo['type'];
imagePath = imageInfo['url'];
ImageProvider imageProvider = AssetImage(imagePath);
switch (type) {
case HcImageType.assets:
imageProvider = AssetImage(imagePath);
break;
case HcImageType.file:
imageProvider = FileImage(File(imagePath));
break;
case HcImageType.base64:
Uint8List bytes = const Base64Decoder().convert(imagePath);
imageProvider = MemoryImage(bytes);
break;
case HcImageType.network:
imageProvider = CachedNetworkImageProvider(imagePath);
break;
}
return imageProvider;
}
}