Flutter 56: 图解自定义 BubbleWidget 气泡插件

简介: 0 基础学习 Flutter,第五十六步:尝试一下自定义气泡插件!

      小菜在学习时需要用到气泡效果,为了更加灵活,小菜封装了一个简单的 flutter_bubble 气泡插件,方便日常的使用;

      小菜准备用 CanvasdrawPath 进行绘制,主要分为三个部分,圆角弧线,普通直线,尖角折线,均可由 drawPath 自带方法绘制;小菜以前整理过关于 Canvas 绘制的小博客,实现很简单;

      小菜绘制了一个简陋的原型图,整体黑框为 Bubble Widget 整体范围;蓝色圆弧为圆角位置;红色尖角可根据上下左右参数进行配置,且只可展示一个,尖角的高度和角度可自由配置,当确定一个尖角位置时,其余三个方向宽高延伸到黑框部分;而橙线则是连接圆角与尖角等直线;中间空余部分为子 Widget 位置;Tips: Child Widget 宽高小于等于 Bubble Widget

绘制圆角

      首先在边角处绘制四个圆弧,直接用 arcTo 即可,需要注意的是:小菜整体以 drawPath 方式实现,准备从左上角开始顺时针绘制,所以绘制圆弧时也是顺时针方向;

void arcTo(Rect rect, double startAngle, double sweepAngle, bool forceMoveTo) {
   assert(_rectIsValid(rect));
   _arcTo(rect.left, rect.top, rect.right, rect.bottom, startAngle, sweepAngle, forceMoveTo);
}

      小菜理解,Rect 为绘制圆角的矩形,包括位置及大小;startAngele 为起始角度;sweepAngle 为绘制弧形角度;小菜需要的四个圆弧大小均为 pi/2,只需调整矩形位置与起始角度即可;

// 逆时针
canvas.drawPath(
    Path()
      ..addArc(Rect.fromCircle(center: Offset(60.0, 60.0), radius: 60.0), 0.0, -pi / 2)
      ..lineTo(0.0, 0.0), paints);
canvas.drawCircle(Offset(120.0, 60.0), 5, paints..color = Colors.indigoAccent);
canvas.drawCircle(Offset(0.0, 0.0), 5, paints..color = Colors.orange);
// 顺时针
canvas.drawPath(
    Path()
      ..addArc(Rect.fromCircle(center: Offset(60.0, 180.0), radius: 60.0), -pi / 2, pi / 2)
      ..lineTo(0.0, 120.0), paints..color = Colors.green);
canvas.drawCircle(Offset(60.0, 120.0), 5, paints..color = Colors.indigoAccent);
canvas.drawCircle(Offset(0.0, 120.0), 5, paints..color = Colors.orange);

绘制尖角

      其次绘制尖角,小菜的尖角是由 lineTo 两段直线拼接起来的,只需要处理起点与终点即可;小菜为了更加灵活,可以设置尖角高度与尖角角度(0 ~ 180),通过三角函数进行计算;

path.lineTo(arrHeight * tan(_angle(arrAngle * 0.5)), 0.0);
path.lineTo(arrHeight * tan(_angle(arrAngle * 0.5)) * 2, arrHeight);

绘制连线

      最后就是将处理好的连接起来,小菜为了适应更多场景,尖角位置也可自由配置,长度为到圆角的距离,默认为边框中间位置;

  1. 尖角在顶部时,距离为左上圆角结束点边距;
  2. 尖角在右侧时,距离为右上圆角结束点边距;
  3. 尖角在底部时,距离为右下圆角结束点边距;
  4. 尖角在左侧时,距离为左下圆角结束点边距;

整体分析

      小菜将配置逻辑编辑好发布到 Pub 库,基本 BubbleWidget 便完成,简单分析一下可配置项;

BubbleWidget(
  this.width,       // 整体高度,并非 Child Widget 宽度
  this.height,      // 整体高度,并非 Child Widget 高度
  this.color,       // 填充颜色,borderColor==null 时也为边框颜色
  this.position, {  // 尖角位置(上下左右)
  Key key,
  this.length = -1.0,       // 尖角距离圆角结束点边距,默认为中点
  this.arrHeight = 12.0,    // 尖角高度
  this.arrAngle = 60.0,     // 尖角角度
  this.radius = 10.0,       // 圆角弧度大小(半径)
  this.strokeWidth = 4.0,   // 边框宽度
  this.style = PaintingStyle.fill,  // 样式(填充或边框)
  this.borderColor,         // 边框颜色(PaintingStyle.stroke 适用)
  this.child,               // 子 Widget
  this.innerPadding = 6.0,  // 子 Widget 距边框边距
}) : super(key: key);
import 'package:flutter/material.dart';
import 'package:flutter_bubble/bubble_widget.dart';

class BubblePage extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return ListView(children: <Widget>[
      Padding(
          padding: EdgeInsets.all(4.0),
          child: Container(
              alignment: Alignment.centerRight,
              child: BubbleWidget(255.0, 60.0, Colors.green.withOpacity(0.7),
                  BubbleArrowDirection.right,
                  child: Text('你好,我是萌新 BubbleWidget!',
                      style: TextStyle(color: Colors.white, fontSize: 16.0))))),
      Padding(
          padding: EdgeInsets.all(4.0),
          child: Container(
              alignment: Alignment.centerLeft,
              child: BubbleWidget(205.0, 60.0,
                  Colors.deepOrange.withOpacity(0.7), BubbleArrowDirection.left,
                  child: Text('你好,你有什么特性化?',
                      style: TextStyle(color: Colors.white, fontSize: 16.0))))),
      Padding(
          padding: EdgeInsets.all(4.0),
          child: Container(
              alignment: Alignment.centerRight,
              child: BubbleWidget(300.0, 90.0, Colors.green.withOpacity(0.7),
                  BubbleArrowDirection.right,
                  child: Text('我可以自定义:\n尖角方向,尖角高度,尖角角度,\n距圆角位置,圆角大小,边框样式等!',
                      style: TextStyle(color: Colors.white, fontSize: 16.0))))),
      Padding(
          padding: EdgeInsets.all(4.0),
          child: Container(
              alignment: Alignment.centerLeft,
              child: BubbleWidget(140.0, 60.0,
                  Colors.deepOrange.withOpacity(0.7), BubbleArrowDirection.left,
                  child: Text('你有什么不足?',
                      style: TextStyle(color: Colors.white, fontSize: 16.0))))),
      Padding(
          padding: EdgeInsets.all(4.0),
          child: Container(
              alignment: Alignment.centerRight,
              child: BubbleWidget(350.0, 60.0, Colors.green.withOpacity(0.7),
                  BubbleArrowDirection.right,
                  child: Text('我现在还不会动态计算高度,只可用作背景!',
                      style: TextStyle(color: Colors.white, fontSize: 16.0))))),
      Padding(
          padding: EdgeInsets.all(4.0),
          child: Container(
              alignment: Alignment.centerLeft,
              child: BubbleWidget(105.0, 60.0,
                  Colors.deepOrange.withOpacity(0.7), BubbleArrowDirection.left,
                  child: Text('继续加油!',
                      style: TextStyle(color: Colors.white, fontSize: 16.0))))),
      Padding(
          padding: EdgeInsets.all(4.0),
          child: Container(
              alignment: Alignment.centerRight,
              child: BubbleWidget(150.0, 140.0, Colors.green.withOpacity(0.7),
                  BubbleArrowDirection.right,
                  child: Image.asset('images/icon_hzw.jpg'))))
    ]);
  }
}

      GitHub 地址      Pub 地址


      自定义 Bubble Widget 是小菜发布的第二款 Pub 插件,还有很多不完善的地方,如有错误请多多指导!

来源:阿策小和尚

目录
相关文章
|
2月前
|
Dart Android开发
鸿蒙Flutter实战:05-使用第三方插件
在鸿蒙Flutter开发中,使用原生功能需借助插件。可自编原生ArkTS代码或采用第三方插件。自编代码通过PlatformView或MethodChannel实现;第三方插件需确保适配鸿蒙,否则须配置替代插件或自行开发。
89 1
鸿蒙Flutter实战:05-使用第三方插件
|
2天前
|
Dart
Flutter 快捷键 和 插件使用
Flutter 快捷键 和 插件使用
Flutter 快捷键 和 插件使用
|
26天前
|
传感器 前端开发 Android开发
在 Flutter 开发中,插件开发与集成至关重要,它能扩展应用功能,满足复杂业务需求
在 Flutter 开发中,插件开发与集成至关重要,它能扩展应用功能,满足复杂业务需求。本文深入探讨了插件开发的基本概念、流程、集成方法、常见类型及开发实例,如相机插件的开发步骤,同时强调了版本兼容性、性能优化等注意事项,并展望了插件开发的未来趋势。
39 2
|
1月前
|
UED 开发者 容器
Flutter&鸿蒙next 的 Sliver 实现自定义滚动效果
Flutter 提供了强大的滚动组件,如 ListView 和 GridView,但当需要更复杂的滚动效果时,Sliver 组件是一个强大的工具。本文介绍了如何使用 Sliver 实现自定义滚动效果,包括 SliverAppBar、SliverList 等常用组件的使用方法,以及通过 CustomScrollView 组合多个 Sliver 组件实现复杂布局的示例。通过具体代码示例,展示了如何实现带有可伸缩 AppBar 和可滚动列表的页面。
110 1
|
1月前
Flutter 自定义组件继承与调用的高级使用方式
本文深入探讨了 Flutter 中自定义组件的高级使用方式,包括创建基本自定义组件、继承现有组件、使用 Mixins 和组合模式等。通过这些方法,您可以构建灵活、可重用且易于维护的 UI 组件,从而提升开发效率和代码质量。
131 1
|
1月前
|
前端开发 开发者
深入探索 Flutter 鸿蒙版的画笔使用与高级自定义动画
本文深入探讨了 Flutter 中的绘图功能,重点介绍了 CustomPainter 和 Canvas 的使用方法。通过示例代码,详细讲解了如何绘制自定义图形、设置 Paint 对象的属性以及实现高级自定义动画。内容涵盖基本绘图、动画基础、渐变动画和路径动画,帮助读者掌握 Flutter 绘图与动画的核心技巧。
80 1
|
1月前
|
Dart UED 开发者
Flutter&鸿蒙next中的按钮封装:自定义样式与交互
在Flutter应用开发中,按钮是用户界面的重要组成部分。Flutter提供了多种内置按钮组件,但有时这些样式无法满足特定设计需求。因此,封装一个自定义按钮组件变得尤为重要。自定义按钮组件可以确保应用中所有按钮的一致性、可维护性和可扩展性,同时提供更高的灵活性,支持自定义颜色、形状和点击事件。本文介绍了如何创建一个名为CustomButton的自定义按钮组件,并详细说明了其样式、形状、颜色和点击事件的处理方法。
86 1
|
1月前
|
Dart 搜索推荐 API
Flutter & 鸿蒙next版本:自定义对话框与表单验证的动态反馈与错误处理
在现代移动应用开发中,用户体验至关重要。本文探讨了如何在 Flutter 与鸿蒙操作系统(HarmonyOS)中创建自定义对话框,并结合表单验证实现动态反馈与错误处理,提升用户体验。通过自定义对话框和表单验证,开发者可以提供更加丰富和友好的交互体验,同时利用鸿蒙next版本拓展应用的受众范围。
84 1
|
2月前
|
编解码 Dart API
鸿蒙Flutter实战:06-使用ArkTs开发Flutter鸿蒙插件
本文介绍了如何开发一个 Flutter 鸿蒙插件,实现 Flutter 与鸿蒙的混合开发及双端消息通信。通过定义 `MethodChannel` 实现 Flutter 侧的 token 存取方法,并在鸿蒙侧编写 `EntryAbility` 和 `ForestPlugin`,使用鸿蒙的首选项 API 完成数据的读写操作。文章还提供了注意事项和参考资料,帮助开发者更好地理解和实现这一过程。
112 0
|
3月前
|
前端开发 搜索推荐
Flutter中自定义气泡框效果的实现
Flutter中自定义气泡框效果的实现
114 3