1. 程式人生 > 其它 >flutter canvas及實現氣泡

flutter canvas及實現氣泡

技術標籤:canvasflutter

canvas瞭解:
Flutter -canvas 使用畫布和路徑繪製自定義形狀和線條曲線
Flutter:成為Canvas繪製大師(一)

Flutter:成為Canvas繪製大師(二)

Flutter:成為Canvas繪製大師(三)
Flutter 氣泡效果合集(全網最全)

以下是我根據上面連結改寫的氣泡:專案需要氣泡的角度是在底部正中間:
效果:
在這裡插入圖片描述

思路:四個彎角利用drawArc畫圓弧,之間的橫豎線利用drawline畫線,小尖叫也是利用drawline實現;


import 'dart:math';

import 'package:flutter/cupertino.dart'
; import 'package:flutter/material.dart'; enum BubbleArrowDirection { top, bottom, right, left, topLeft } class BubbleWidget extends StatelessWidget { // 尖角位置 final position; // 尖角高度 var arrHeight; // 尖角角度 var arrAngle; // 圓角半徑 var radius; // 寬度 final width; // 高度 final height; // 邊距
double length; // 顏色 Color color; // 邊框顏色 Color borderColor; // 邊框寬度 final strokeWidth; // 填充樣式 final style; // 子 Widget final child; // 子 Widget 與起泡間距 var innerPadding; BubbleWidget( this.width, this.height, this.color , this.position, { Key key,
this.length = 1, this.arrHeight = 12.0, this.arrAngle = 60.0, this.radius = 10.0, this.strokeWidth = 4.0, this.style = PaintingStyle.fill, this.borderColor, this.child, this.innerPadding = 6.0, }) : super(key: key); @override Widget build(BuildContext context) { if (style == PaintingStyle.stroke && borderColor == null) { // borderColor = color; } if (arrAngle < 0.0 || arrAngle >= 180.0) { arrAngle = 60.0; } if (arrHeight < 0.0) { arrHeight = 0.0; } if (radius < 0.0 || radius > width * 0.5 || radius > height * 0.5) { radius = 0.0; } if (position == BubbleArrowDirection.top || position == BubbleArrowDirection.bottom) { if (length < 0.0 || length >= width - 2 * radius) { length = width * 0.5 - arrHeight * tan(_angle(arrAngle * 0.5)) - radius; } } else { if (length < 0.0 || length >= height - 2 * radius) { length = height * 0.5 - arrHeight * tan(_angle(arrAngle * 0.5)) - radius; } } if (innerPadding < 0.0 || innerPadding >= width * 0.5 || innerPadding >= height * 0.5) { innerPadding = 2.0; } Widget bubbleWidget; if (style == PaintingStyle.fill) { bubbleWidget = Container( width: width, height: height, child: Stack(children: <Widget>[ CustomPaint( painter: BubbleCanvas(context, width, height, color, position, arrHeight, arrAngle, radius, strokeWidth, style, length)), CustomPaint( painter: BubbleCanvas( context, width, height, borderColor, position, arrHeight, arrAngle, radius, strokeWidth, PaintingStyle.stroke, length)), _paddingWidget() ])); } else { bubbleWidget = Container( width: width, height: height, child: Stack(children: <Widget>[ CustomPaint( painter: BubbleCanvas( context, width, height, color, position, arrHeight, arrAngle, radius, strokeWidth, PaintingStyle.fill, length)), CustomPaint( painter: BubbleCanvas( context, width, height, borderColor, position, arrHeight, arrAngle, radius, strokeWidth, PaintingStyle.stroke, length)), _paddingWidget() ])); } return bubbleWidget; } Widget _paddingWidget() { return Padding( padding: EdgeInsets.only( top: (position == BubbleArrowDirection.top) ? arrHeight + innerPadding : innerPadding, right: (position == BubbleArrowDirection.right) ? arrHeight + innerPadding : innerPadding, bottom: (position == BubbleArrowDirection.bottom) ? arrHeight + innerPadding : innerPadding, left: (position == BubbleArrowDirection.left) ? arrHeight + innerPadding : innerPadding), child: Center(child: this.child)); } } class BubbleCanvas extends CustomPainter { BuildContext context; final position; final arrHeight; final arrAngle; final radius; final width; final height; final length; final color; final strokeWidth; final style; BubbleCanvas( this.context, this.width, this.height, this.color, this.position, this.arrHeight, this.arrAngle, this.radius, this.strokeWidth, this.style, this.length); @override void paint(Canvas canvas, Size size) { Path path = Path(); path.arcTo( Rect.fromCircle( center: Offset( (position == BubbleArrowDirection.left) ? radius + arrHeight : radius, (position == BubbleArrowDirection.top) ? radius + arrHeight : radius), radius: radius), pi, pi * 0.5, false);//畫左上半弧 if (position == BubbleArrowDirection.top) { path.lineTo(length + radius, arrHeight); path.lineTo( length + radius + arrHeight * tan(_angle(arrAngle * 0.5)), 0.0); path.lineTo(length + radius + arrHeight * tan(_angle(arrAngle * 0.5)) * 2, arrHeight); } path.lineTo( (position == BubbleArrowDirection.right) ? width - radius - arrHeight : width - radius, (position == BubbleArrowDirection.top) ? arrHeight : 0.0);//畫top橫線 path.arcTo( Rect.fromCircle( center: Offset( (position == BubbleArrowDirection.right) ? width - radius - arrHeight : width - radius, (position == BubbleArrowDirection.top) ? radius + arrHeight : radius), radius: radius), -pi * 0.5, pi * 0.5, false);//畫右上弧度 if (position == BubbleArrowDirection.right) { path.lineTo(width - arrHeight, length + radius); path.lineTo( width, length + radius + arrHeight * tan(_angle(arrAngle * 0.5))); path.lineTo(width - arrHeight, length + radius + arrHeight * tan(_angle(arrAngle * 0.5)) * 2); } path.lineTo( (position == BubbleArrowDirection.right) ? width - arrHeight : width, (position == BubbleArrowDirection.bottom) ? height - radius - arrHeight : height - radius);//畫右橫線 path.arcTo( Rect.fromCircle( center: Offset( (position == BubbleArrowDirection.right) ? width - radius - arrHeight : width - radius, (position == BubbleArrowDirection.bottom) ? height - radius - arrHeight : height - radius), radius: radius), pi * 0, pi * 0.5, false);//畫右下弧 if (position == BubbleArrowDirection.bottom) { path.lineTo(width/2+arrHeight*tan(_angle(arrAngle * 0.5)), height - arrHeight);//畫右下斜邊 path.lineTo( width/2, height);//最低點 path.lineTo( width/2-arrHeight*tan(_angle(arrAngle * 0.5)), height - arrHeight);//左下斜邊 } path.lineTo( (position == BubbleArrowDirection.left) ? radius + arrHeight : radius, (position == BubbleArrowDirection.bottom) ? height - arrHeight : height); path.arcTo( Rect.fromCircle( center: Offset( (position == BubbleArrowDirection.left) ? radius + arrHeight : radius, (position == BubbleArrowDirection.bottom) ? height - radius - arrHeight : height - radius), radius: radius), pi * 0.5, pi * 0.5, false);//畫左下弧 if (position == BubbleArrowDirection.left) { path.lineTo(arrHeight, height - radius - length); path.lineTo(0.0, height - radius - length - arrHeight * tan(_angle(arrAngle * 0.5))); path.lineTo( arrHeight, height - radius - length - arrHeight * tan(_angle(arrAngle * 0.5)) * 2); } path.lineTo((position == BubbleArrowDirection.left) ? arrHeight : 0.0, (position == BubbleArrowDirection.top) ? radius + arrHeight : radius);//畫左橫線 // path.fillType(); path.close();//閉合 // Paint paint1=new Paint(); canvas.drawPath( path, Paint() ..color=color ..style = style ..strokeCap = StrokeCap.round ..strokeWidth = strokeWidth); } @override bool shouldRepaint(CustomPainter oldDelegate) { return true; } } double _angle(angle) { return angle * pi / 180; }

使用:

Center(
          child: BubbleWidget(100.0,40.0,Colors.orange,BubbleArrowDirection.bottom,radius: 5.0,strokeWidth: 4.0,borderColor: Colors.blueAccent
            ,child: Text("dddd"),),
        )