最近一直在学习flutter,基本的组件和布局自己也都摸了一遍。随着时间的推移,学习的东西越多,做的东西也就多了,也会有个别组件,在flutter原生中无法实现,比如本文要讲的虚线边框,在网上找了一圈,有是有的,但还是不能满足我的需求,我是希望可以自定义虚线框,除了虚线的间隔,宽度和颜色,我还希望能够某一边的边框可以忽略,于是自己仿照着列子写了一个,顺便学习了flutter的CustomPaint和CustomPainter这两个自定义组件的重要类型。当然有机会会继续改造,将边框的类型更加多样化,我还是先上代码吧。
import 'package:flutter/material.dart';
import 'dart:math' as math;
class CustomDashedRect extends StatelessWidget {
final Color color;
final double strokeWidth;
final double gap;
final Widget child;
final Map paintrect;
CustomDashedRect({
@required this.child,
this.color=Colors.black,
this.strokeWidth = 1.0, /*边框的宽度*/
this.gap =2, /*虚边框的间隙*/
this.paintrect=const{"left":true,"top":true,"right":true,"bottom":true}, /*左右上下,代表是否要描绘边框*/
});
@override
Widget build(BuildContext context) {
return Stack(
children: <Widget>[
Positioned.fill(
child: CustomPaint(
painter: DashRectPainter(color:this.color, strokeWidth: this.strokeWidth,gap:this.gap,paintrect: this.paintrect),
)),
Padding(
padding: const EdgeInsets.all(2),
child: child,
),
],
);
}
}
class DashRectPainter extends CustomPainter {
double strokeWidth;
Color color;
double gap;
Map paintrect;
DashRectPainter(
{this.strokeWidth = 5.0, this.color = Colors.red, this.gap = 5.0,this.paintrect=const {"left":true,"top":true,"right":true,"bottom":true}});
@override
void paint(Canvas canvas, Size size) {
Paint dashedPaint = Paint()
..color = color
..strokeWidth = strokeWidth
..style = PaintingStyle.stroke;
double x = size.width;
double y = size.height;
if(this.paintrect["top"]){
Path _topPath= getDashedPath(
a: math.Point(0, 0),
b: math.Point(x, 0),
gap: gap,
);
canvas.drawPath(_topPath, dashedPaint);
}
if(this.paintrect['right']){
Path _rightPath = getDashedPath(
a: math.Point(x, 0),
b: math.Point(x, y),
gap: gap,
);
canvas.drawPath(_rightPath, dashedPaint);
}
if(this.paintrect['bottom']){
Path _bottomPath = getDashedPath(
a: math.Point(0, y),
b: math.Point(x, y),
gap: gap,
);
canvas.drawPath(_bottomPath, dashedPaint);
}
if(this.paintrect['left']){
Path _leftPath= getDashedPath(
a: math.Point(0, 0),
b: math.Point(0.001, y),
gap: gap,
);
canvas.drawPath(_leftPath, dashedPaint);
}
}
Path getDashedPath({
@required math.Point<double> a,
@required math.Point<double> b,
@required gap,
}) {
Size size = Size(b.x - a.x, b.y - a.y);
Path path = Path();
path.moveTo(a.x, a.y);
bool shouldDraw = true;
math.Point currentPoint = math.Point(a.x, a.y);
num radians = math.atan(size.height / size.width);
num dx = math.cos(radians) * gap < 0
? math.cos(radians) * gap * -1
: math.cos(radians) * gap;
num dy = math.sin(radians) * gap < 0
? math.sin(radians) * gap * -1
: math.sin(radians) * gap;
while (currentPoint.x <= b.x && currentPoint.y <= b.y) {
shouldDraw
? path.lineTo(currentPoint.x, currentPoint.y)
: path.moveTo(currentPoint.x, currentPoint.y);
shouldDraw = !shouldDraw;
currentPoint = math.Point(
currentPoint.x + dx,
currentPoint.y + dy,
);
}
return path;
}
@override
bool shouldRepaint(CustomPainter oldDelegate) {
return true;
}
}