你可以不用,但你必须得会!Flutter实现微信聊天框

1,545 阅读2分钟

今天给大家分享Flutter中一个聊天气泡框的做法,简单实用,收藏起来,说不定哪天能用的上

先看效果

高度还原了微信聊天气泡框,支持气泡框自动伸缩,区分发送方和接收方

image.png

实现原理

用到了主要是Flutter中的PhysicalShape实现自定义形状图层,通过自定义形状的路径既可实现不同的形状,平时大家用的ClipRRect来实现裁剪圆角矩形也是用的同样的技术。

PhysicalShape

根据官方文档的解释,PhysicalShape可以把child组件进行剪切成path描述的形状,我们这里正好利用这个功能来制作聊天气泡框。

const PhysicalShape({
   super.key,
   required this.clipper,
   this.clipBehavior = Clip.none,
   this.elevation = 0.0,
   required this.color,
   this.shadowColor = const Color(0xFF000000),
   super.child,
 }) : assert(elevation >= 0.0);
  • clipper 执行真正自定义形状的逻辑
  • clipBehavior, 如果内容溢出了,要如何裁剪,比如是否要抗锯齿平滑裁剪等等选项
  • elevation 控制投影高度
  • color 形状填充色
  • shadowColor 投影的颜色

重点是CustomClipper

根据官方文档,CustomClipper 是一个抽象类,我们常用的裁剪组件

  • ClipRect
  • ClipRRect
  • ClipOval
  • ClipPath
  • ShapeBorderClipper

都是继承它来实现的

它重点就2个方法:

  • getClip 返回一个path,CustomClipper就是根据这个path来绘制形状图层
  • shouldReclip 决定要不要进行重新绘制

开始裁剪

思路: 先画一个矩形,然后在一侧画一个小三角形,这里要注意区分的是发送方、接收方,小三角形的位置是不同的

@override
 Path getClip(Size size) {
   var path = Path();

   if (isMe) {
     path.addRRect(
       RRect.fromLTRBR(
         0,
         0,
         size.width - nipSize,
         size.height,
         Radius.circular(radius),
       ),
     );

     var path2 = Path();
     path2.lineTo(nipSize, nipSize);
     path2.lineTo(0, 2 * nipSize);
     path2.lineTo(0, 0);

     path.addPath(
       path2,
       Offset(size.width - nipSize, offset + 2 * nipSize),
     );
   } else {
     path.addRRect(
       RRect.fromLTRBR(
         nipSize,
         0,
         size.width - nipSize,
         size.height,
         Radius.circular(radius),
       ),
     );

     var path2 = Path();
     path2.lineTo(0, 2 * nipSize);
     path2.lineTo(-nipSize, nipSize);
     path2.lineTo(0, 0);

     path.addPath(path2, Offset(nipSize, offset + 2 * nipSize));
   }

   return path;
 }

好了,是不是很简单呢,稍微封装一下,就可以用在自己的项目中了 欢迎关注微信公众号 【技术万有引力】,分享更多实用案例