【Flutter小技巧06】--- Flutter折叠头像、毛玻璃效果、消息提示的实现

1,189 阅读2分钟

小知识,大挑战!本文正在参与“程序员必备小知识”创作活动。

本文已参与「掘力星计划」,赢取创作大礼包,挑战创作激励金。

Flutter小技巧目录
【Flutter小技巧01】--- TextField文本垂直居中
【Flutter小技巧02】Flutter环境变量配置
【Flutter小技巧03】-- 常见报错记录
【Flutter小技巧04】--- Flutter架构设计
【Flutter小技巧05】--- Flutter混编集成方案探讨

📃 需求是学习技术最有效的动力

前言:需求是不是的变化,作为开发要时刻应变需求的变化而改变。今天遇到一个折叠头像的需求。吗毛玻璃头像+折叠头像+新消息数量,先看效果图:

image.png

实现: 第一步:实现折叠头像效果;

Positioned 组件可以实现折腾效果:off是位置的变化,这里封装了一个方法,折叠头像+毛玻璃效果

/// 折叠头像
/// itemType 是我根据需求实现的头像类型,我这边喜欢和来访,count是头像的个数
List<Widget> _getStackItems(MessageHeaderItemType itemType, int count) {
  List<Widget> _list = [];
  for (var i = 0; i < count; i++) {
    double off = 20.0 * i;
    _list.add(Positioned(
      left: off,
      child: Container(
        width: 30,
        height: 30,
        decoration: BoxDecoration(
          border: Border.all(color: Colors.white, width: 1),
          borderRadius: BorderRadius.circular(15),
        ),
        child: Stack(
          children: <Widget>[
            //约束性盒子
            Container(
              decoration:
                  Style.setBoxDecoration(15, color: Colors.transparent),
              child: AvatarWidget(
                itemType == MessageHeaderItemType.LikeMe
                    ? likeHeadList.isNotEmpty
                        ? likeHeadList[i]?.user_info?.header_url ??
                            Constant.defaultAvatarUrl
                        : Constant.defaultAvatarUrl
                    : visitingHeadList.isNotEmpty
                        ? visitingHeadList[i]?.user_info?.header_url ??
                            Constant.defaultAvatarUrl
                        : Constant.defaultAvatarUrl,
                width: 30,
                height: 30,
                fit: BoxFit.fill,
                borderRadius: BorderRadius.circular(15),
              ),
            ),
            Center(
              //可裁切的矩形
              child: ClipRRect(
                borderRadius: BorderRadius.circular(15),
                //背景过滤器
                child: BackdropFilter(
                  filter: ImageFilter.blur(sigmaX: 5.0, sigmaY: 5.0),
                  child: Opacity(
                    opacity: 0.5,
                    child: Container(
                      width: 30.0,
                      height: 30.0,
                      decoration: BoxDecoration(
                        color: Colors.black,
                        borderRadius: BorderRadius.circular(15),
                      ),
                    ),
                  ),
                ),
              ),
            )
          ],
        ),
      ),
    ));
  }
  return _list;
}
    

第二步:实现头像毛玻璃效率;

Container(
  width: 30,
  height: 30,
  decoration: BoxDecoration(
    border: Border.all(color: Colors.white, width: 1),
    borderRadius: BorderRadius.circular(15),
  ),
  child: Stack(
    children: <Widget>[
      //约束性盒子
      Container(
        decoration:
            Style.setBoxDecoration(15, color: Colors.transparent),
        child: AvatarWidget(
          itemType == MessageHeaderItemType.LikeMe
              ? likeHeadList.isNotEmpty
                  ? likeHeadList[i]?.user_info?.header_url ??
                      Constant.defaultAvatarUrl
                  : Constant.defaultAvatarUrl
              : visitingHeadList.isNotEmpty
                  ? visitingHeadList[i]?.user_info?.header_url ??
                      Constant.defaultAvatarUrl
                  : Constant.defaultAvatarUrl,
          width: 30,
          height: 30,
          fit: BoxFit.fill,
          borderRadius: BorderRadius.circular(15),
        ),
      ),
      Center(
        //可裁切的矩形
        child: ClipRRect(
          borderRadius: BorderRadius.circular(15),
          //背景过滤器
          child: BackdropFilter(
            filter: ImageFilter.blur(sigmaX: 5.0, sigmaY: 5.0),
            child: Opacity(
              opacity: 0.5,
              child: Container(
                width: 30.0,
                height: 30.0,
                decoration: BoxDecoration(
                  color: Colors.black,
                  borderRadius: BorderRadius.circular(15),
                ),
              ),
            ),
          ),
        ),
      )
    ],
  ),
)

第三步:实现右上角消息数量提示; 使用badges插件 轻松搞定:可以自己封装下。

附:完整代码:封装的方法,可以直接使用,实现了三个需求:头像毛玻璃+头像折叠效果+消息提示。

/// 头像
Widget _buildHeadRedWidget(MessageHeaderItemType itemType, int unCount) {
  int count = 1;
  if (unCount == 1) {
    count = 1;
  } else if (unCount == 2) {
    count = 2;
  } else {
    count = 3;
  }
  return Container(
    height: 30,
    width: 70,
    alignment: Alignment.center,
    child: BadgeWidget(
      unCount: unCount,
      position: BadgePosition.topEnd(
          top: -7,
          end: count == 1
              ? 13
              : count == 2
                  ? 5
                  : unCount >= 10
                      ? -12
                      : -5),
      child: Row(
        mainAxisAlignment: MainAxisAlignment.center,
        children: [
          SizedBox(
            // 30 50 70
            width: count == 1
                ? 30
                : count == 2
                    ? 50
                    : 70,
            child: Stack(
              children: _getStackItems(itemType, count),
            ),
          ),
        ],
      ),
    ),
  );
}

/// 折叠头像
List<Widget> _getStackItems(MessageHeaderItemType itemType, int count) {
  List<Widget> _list = [];
  for (var i = 0; i < count; i++) {
    double off = 20.0 * i;
    _list.add(Positioned(
      left: off,
      child: Container(
        width: 30,
        height: 30,
        decoration: BoxDecoration(
          border: Border.all(color: Colors.white, width: 1),
          borderRadius: BorderRadius.circular(15),
        ),
        child: Stack(
          children: <Widget>[
            //约束性盒子
            Container(
              decoration:
                  Style.setBoxDecoration(15, color: Colors.transparent),
              child: AvatarWidget(
                itemType == MessageHeaderItemType.LikeMe
                    ? likeHeadList.isNotEmpty
                        ? likeHeadList[i]?.user_info?.header_url ??
                            Constant.defaultAvatarUrl
                        : Constant.defaultAvatarUrl
                    : visitingHeadList.isNotEmpty
                        ? visitingHeadList[i]?.user_info?.header_url ??
                            Constant.defaultAvatarUrl
                        : Constant.defaultAvatarUrl,
                width: 30,
                height: 30,
                fit: BoxFit.fill,
                borderRadius: BorderRadius.circular(15),
              ),
            ),
            Center(
              //可裁切的矩形
              child: ClipRRect(
                borderRadius: BorderRadius.circular(15),
                //背景过滤器
                child: BackdropFilter(
                  filter: ImageFilter.blur(sigmaX: 5.0, sigmaY: 5.0),
                  child: Opacity(
                    opacity: 0.5,
                    child: Container(
                      width: 30.0,
                      height: 30.0,
                      decoration: BoxDecoration(
                        color: Colors.black,
                        borderRadius: BorderRadius.circular(15),
                      ),
                    ),
                  ),
                ),
              ),
            )
          ],
        ),
      ),
    ));
  }
  return _list;
}

未实现的时候需要考虑下,实现了就觉得不难,只为记录开发中的点滴...