美文网首页
Flutter 重复造轮子 (2) Avatar 头像显示组件的

Flutter 重复造轮子 (2) Avatar 头像显示组件的

作者: 半城半离人 | 来源:发表于2023-09-08 10:08 被阅读0次

详细可以访问仓库 HcUi: 重复创造Flutter 的轮子 在原有组件上拓展 展现出新的特性 (gitee.com)

介绍

CircleAvatar组件增强版.头像组件,可以适配文字,图片以及图标。可以设置背景颜色为渐变不局限于圆形 可以增加阴影以及边框
根据官方圆形头像组件 修改 不局限于圆形可以变化任意形状 实现方式为AnimatedContainer的 foregroundDecoration


Screenshot_2023-09-07-16-39-51-0900154547.png

代码演示

基础用法

            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;
  }
}

相关文章

网友评论

      本文标题:Flutter 重复造轮子 (2) Avatar 头像显示组件的

      本文链接:https://www.haomeiwen.com/subject/cjybsdtx.html