由于您的用例超出了Ffltter提供的默认行为(通过Border
),因此利用Flight的开放源码特性并判断底层类是很有用的.
通过查看BoxDecoration
‘S边界属性,我们可以看到该参数接受BoxBorder
.这就是Border
实现的内容,因为Border
不包括这个用例,所以我们可以创建BoxBorder
的自定义实现.
我已经实现了一个名为InclinedBorder
的自定义实现,它可以有一对垂直或水平倾斜的边框.创建BoxBorder
的自定义实现需要告诉Ffltter如何在paint
方法中通过画布绘制边框,这需要一些数学运算.
最终结果
InclinedBorder
implementation:
class InclinedBorder extends BoxBorder {
final Axis inclineAxis;
final double inclinedBorderStartWidth;
final double inclinedBorderEndWidth;
final double startBorderConstantWidth;
final double endBorderConstantWidth;
// The paint implementation have a minor gap between the border-sides this
// corrects it.
final double gapCorrection = 0.5;
const InclinedBorder({
required this.inclineAxis,
required this.inclinedBorderStartWidth,
required this.inclinedBorderEndWidth,
required this.startBorderConstantWidth,
required this.endBorderConstantWidth,
});
@override
void paint(
Canvas canvas,
Rect rect, {
TextDirection? textDirection,
BoxShape shape = BoxShape.rectangle,
BorderRadius? borderRadius,
}) {
final paint = Paint();
switch (inclineAxis) {
case Axis.horizontal:
paint.strokeWidth = startBorderConstantWidth;
canvas.drawLine(
rect.topLeft - Offset(startBorderConstantWidth / 2, gapCorrection),
rect.bottomLeft -
Offset(startBorderConstantWidth / 2, -gapCorrection),
paint);
paint.strokeWidth = endBorderConstantWidth;
canvas.drawLine(
rect.topRight +
Offset(endBorderConstantWidth / 2, -gapCorrection),
rect.bottomRight +
Offset(endBorderConstantWidth / 2, gapCorrection),
paint);
paint.style = PaintingStyle.fill;
Path path = Path();
path.moveTo(
rect.topLeft.dx - startBorderConstantWidth, rect.topLeft.dy);
path.lineTo(rect.topLeft.dx - startBorderConstantWidth,
rect.topLeft.dy - inclinedBorderStartWidth);
path.lineTo(rect.topRight.dx + endBorderConstantWidth,
rect.topRight.dy - inclinedBorderEndWidth);
path.lineTo(
rect.topRight.dx + endBorderConstantWidth, rect.topRight.dy);
path.moveTo(
rect.bottomLeft.dx - startBorderConstantWidth, rect.bottomLeft.dy);
path.lineTo(rect.bottomLeft.dx - startBorderConstantWidth,
rect.bottomLeft.dy + inclinedBorderStartWidth);
path.lineTo(rect.bottomRight.dx + endBorderConstantWidth,
rect.bottomRight.dy + inclinedBorderEndWidth);
path.lineTo(
rect.bottomRight.dx + endBorderConstantWidth, rect.bottomRight.dy);
canvas.drawPath(path, paint);
break;
case Axis.vertical:
paint.strokeWidth = startBorderConstantWidth;
canvas.drawLine(
rect.topLeft - Offset(gapCorrection, startBorderConstantWidth / 2),
rect.topRight -
Offset(-gapCorrection, startBorderConstantWidth / 2),
paint);
paint.strokeWidth = endBorderConstantWidth;
canvas.drawLine(
rect.bottomLeft +
Offset(-gapCorrection, endBorderConstantWidth / 2),
rect.bottomRight +
Offset(gapCorrection, endBorderConstantWidth / 2),
paint);
paint.style = PaintingStyle.fill;
paint.strokeWidth = 1;
Path path = Path();
path.moveTo(
rect.topLeft.dx, rect.topLeft.dy - startBorderConstantWidth);
path.lineTo(rect.topLeft.dx - inclinedBorderStartWidth,
rect.topLeft.dy - startBorderConstantWidth);
path.lineTo(rect.bottomLeft.dx - inclinedBorderEndWidth,
rect.bottomLeft.dy + endBorderConstantWidth);
path.lineTo(
rect.bottomLeft.dx, rect.bottomLeft.dy + endBorderConstantWidth);
path.moveTo(
rect.topRight.dx, rect.topRight.dy - startBorderConstantWidth);
path.lineTo(rect.topRight.dx + inclinedBorderStartWidth,
rect.topRight.dy - startBorderConstantWidth);
path.lineTo(rect.bottomRight.dx + inclinedBorderEndWidth,
rect.bottomRight.dy + endBorderConstantWidth);
path.lineTo(
rect.bottomRight.dx, rect.bottomRight.dy + endBorderConstantWidth);
canvas.drawPath(path, paint);
break;
}
}
@override
BorderSide get top => BorderSide(
width: inclineAxis == Axis.horizontal
? max(inclinedBorderStartWidth, inclinedBorderEndWidth)
: startBorderConstantWidth,
);
@override
BorderSide get bottom => BorderSide(
width: inclineAxis == Axis.horizontal
? max(inclinedBorderStartWidth, inclinedBorderEndWidth)
: endBorderConstantWidth,
);
@override
EdgeInsetsGeometry get dimensions {
switch (inclineAxis) {
case Axis.horizontal:
return EdgeInsets.fromLTRB(
startBorderConstantWidth,
max(inclinedBorderStartWidth, inclinedBorderEndWidth),
endBorderConstantWidth,
max(inclinedBorderStartWidth, inclinedBorderEndWidth),
);
case Axis.vertical:
return EdgeInsets.fromLTRB(
max(inclinedBorderStartWidth, inclinedBorderEndWidth),
startBorderConstantWidth,
max(inclinedBorderStartWidth, inclinedBorderEndWidth),
endBorderConstantWidth,
);
}
}
@override
bool get isUniform => false;
// TODO: This has not been implemented.
@override
ShapeBorder scale(double t) => throw UnimplementedError();
}
图像背后的用法/代码示例
注意Container
‘S边距和InclinedBorder
/BoxBorder
’S尺寸属性的使用,以正确设置边距.
import 'dart:math';
import 'package:flutter/material.dart';
main() => runApp(const MaterialApp(home: BorderTestScreen()));
class BorderTestScreen extends StatelessWidget {
const BorderTestScreen({super.key});
@override
Widget build(BuildContext context) {
InclinedBorder border1 = const InclinedBorder(
inclineAxis: Axis.horizontal,
inclinedBorderStartWidth: 20,
inclinedBorderEndWidth: 10,
startBorderConstantWidth: 20,
endBorderConstantWidth: 20,
);
InclinedBorder border2 = const InclinedBorder(
inclineAxis: Axis.vertical,
inclinedBorderStartWidth: 20,
inclinedBorderEndWidth: 10,
startBorderConstantWidth: 20,
endBorderConstantWidth: 20,
);
return Scaffold(
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.center,
children: [
Container(
margin: border1.dimensions,
decoration: BoxDecoration(
color: Colors.green,
border: border1,
),
child: const SizedBox(
width: 300,
height: 100,
),
),
const SizedBox(
height: 8,
),
Container(
margin: border2.dimensions,
decoration: BoxDecoration(
color: Colors.green,
border: border2,
),
child: const SizedBox(
width: 300,
height: 100,
),
)
]),
),
);
}
}
注意:如果要使用它,请考虑创建一个抽象化维度逻辑的小部件.
希望这个能帮上忙!