Flutter 56: 圖解自定義 BubbleWidget 氣泡插件

??????小菜在學習時需要用到氣泡效果,為了更加靈活背伴,小菜封裝了一個簡單的 flutter_bubble 氣泡插件,方便日常的使用;

??????小菜準備用 CanvasdrawPath 進行繪制烁试,主要分為三個部分,圓角弧線拢肆,普通直線减响,尖角折線,均可由 drawPath 自帶方法繪制郭怪;小菜以前整理過關(guān)于 Canvas 繪制的小博客支示,實現(xiàn)很簡單;

??????小菜繪制了一個簡陋的原型圖鄙才,整體黑框為 Bubble Widget 整體范圍悼院;藍色圓弧為圓角位置;紅色尖角可根據(jù)上下左右參數(shù)進行配置咒循,且只可展示一個据途,尖角的高度和角度可自由配置,當確定一個尖角位置時叙甸,其余三個方向?qū)捀哐由斓胶诳虿糠钟币剑欢染€則是連接圓角與尖角等直線;中間空余部分為子 Widget 位置裆蒸;Tips: Child Widget 寬高小于等于 Bubble Widget熔萧;

繪制圓角

??????首先在邊角處繪制四個圓弧,直接用 arcTo 即可僚祷,需要注意的是:小菜整體以 drawPath 方式實現(xiàn)佛致,準備從左上角開始順時針繪制,所以繪制圓弧時也是順時針方向辙谜;

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萍桌,只需調(diào)整矩形位置與起始角度即可;

// 逆時針
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)藕施,通過三角函數(shù)進行計算;

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

繪制連線

??????最后就是將處理好的連接起來畔派,小菜為了適應更多場景铅碍,尖角位置也可自由配置,長度為到圓角的距離线椰,默認為邊框中間位置胞谈;

  1. 尖角在頂部時,距離為左上圓角結(jié)束點邊距憨愉;
  2. 尖角在右側(cè)時烦绳,距離為右上圓角結(jié)束點邊距;
  3. 尖角在底部時配紫,距離為右下圓角結(jié)束點邊距径密;
  4. 尖角在左側(cè)時,距離為左下圓角結(jié)束點邊距躺孝;

整體分析

??????小菜將配置邏輯編輯好發(fā)布到 Pub 庫享扔,基本 BubbleWidget 便完成底桂,簡單分析一下可配置項;

BubbleWidget(
  this.width,       // 整體高度惧眠,并非 Child Widget 寬度
  this.height,      // 整體高度籽懦,并非 Child Widget 高度
  this.color,       // 填充顏色,borderColor==null 時也為邊框顏色
  this.position, {  // 尖角位置(上下左右)
  Key key,
  this.length = -1.0,       // 尖角距離圓角結(jié)束點邊距氛魁,默認為中點
  this.arrHeight = 12.0,    // 尖角高度
  this.arrAngle = 60.0,     // 尖角角度
  this.radius = 10.0,       // 圓角弧度大小(半徑)
  this.strokeWidth = 4.0,   // 邊框?qū)挾?  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('我現(xiàn)在還不會動態(tài)計算高度洞就,只可用作背景盆繁!',
                      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('繼續(xù)加油!',
                      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 是小菜發(fā)布的第二款 Pub 插件旬蟋,還有很多不完善的地方油昂,如有錯誤請多多指導!

來源:阿策小和尚

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末倾贰,一起剝皮案震驚了整個濱河市冕碟,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌匆浙,老刑警劉巖安寺,帶你破解...
    沈念sama閱讀 206,968評論 6 482
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異首尼,居然都是意外死亡挑庶,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,601評論 2 382
  • 文/潘曉璐 我一進店門软能,熙熙樓的掌柜王于貴愁眉苦臉地迎上來迎捺,“玉大人,你說我怎么就攤上這事查排〉手Γ” “怎么了?”我有些...
    開封第一講書人閱讀 153,220評論 0 344
  • 文/不壞的土叔 我叫張陵跋核,是天一觀的道長岖瑰。 經(jīng)常有香客問我叛买,道長,這世上最難降的妖魔是什么锭环? 我笑而不...
    開封第一講書人閱讀 55,416評論 1 279
  • 正文 為了忘掉前任聪全,我火速辦了婚禮,結(jié)果婚禮上辅辩,老公的妹妹穿的比我還像新娘。我一直安慰自己娃圆,他們只是感情好玫锋,可當我...
    茶點故事閱讀 64,425評論 5 374
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著讼呢,像睡著了一般撩鹿。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上悦屏,一...
    開封第一講書人閱讀 49,144評論 1 285
  • 那天节沦,我揣著相機與錄音,去河邊找鬼础爬。 笑死甫贯,一個胖子當著我的面吹牛,可吹牛的內(nèi)容都是我干的看蚜。 我是一名探鬼主播叫搁,決...
    沈念sama閱讀 38,432評論 3 401
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼供炎!你這毒婦竟也來了渴逻?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 37,088評論 0 261
  • 序言:老撾萬榮一對情侶失蹤音诫,失蹤者是張志新(化名)和其女友劉穎惨奕,沒想到半個月后,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體竭钝,經(jīng)...
    沈念sama閱讀 43,586評論 1 300
  • 正文 獨居荒郊野嶺守林人離奇死亡梨撞,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 36,028評論 2 325
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了蜓氨。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片聋袋。...
    茶點故事閱讀 38,137評論 1 334
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖穴吹,靈堂內(nèi)的尸體忽然破棺而出幽勒,到底是詐尸還是另有隱情,我是刑警寧澤港令,帶...
    沈念sama閱讀 33,783評論 4 324
  • 正文 年R本政府宣布啥容,位于F島的核電站锈颗,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏咪惠。R本人自食惡果不足惜击吱,卻給世界環(huán)境...
    茶點故事閱讀 39,343評論 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望遥昧。 院中可真熱鬧覆醇,春花似錦、人聲如沸炭臭。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,333評論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽鞋仍。三九已至常摧,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間威创,已是汗流浹背落午。 一陣腳步聲響...
    開封第一講書人閱讀 31,559評論 1 262
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留肚豺,地道東北人溃斋。 一個月前我還...
    沈念sama閱讀 45,595評論 2 355
  • 正文 我出身青樓,卻偏偏與公主長得像详炬,于是被迫代替她去往敵國和親盐类。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 42,901評論 2 345

推薦閱讀更多精彩內(nèi)容