|
|
|
import 'package:flutter/material.dart';
|
|
|
|
|
|
|
|
class ScannerOverlay extends ShapeBorder {
|
|
|
|
const ScannerOverlay({
|
|
|
|
this.borderColor = Colors.red,
|
|
|
|
this.borderWidth = 3.0,
|
|
|
|
this.overlayColor = const Color.fromRGBO(0, 0, 0, 40),
|
|
|
|
this.borderRadius = 0,
|
|
|
|
this.borderLength = 40,
|
|
|
|
this.cutOutSize = 250,
|
|
|
|
}) : assert(borderLength <= cutOutSize / 2 + borderWidth * 2,
|
|
|
|
"Border can't be larger than ${cutOutSize / 2 + borderWidth * 2}");
|
|
|
|
|
|
|
|
final Color borderColor;
|
|
|
|
final double borderWidth;
|
|
|
|
final Color overlayColor;
|
|
|
|
final double borderRadius;
|
|
|
|
final double borderLength;
|
|
|
|
final double cutOutSize;
|
|
|
|
|
|
|
|
@override
|
|
|
|
EdgeInsetsGeometry get dimensions => const EdgeInsets.all(10);
|
|
|
|
|
|
|
|
@override
|
|
|
|
Path getInnerPath(Rect rect, {TextDirection? textDirection}) {
|
|
|
|
return Path()
|
|
|
|
..fillType = PathFillType.evenOdd
|
|
|
|
..addPath(getOuterPath(rect), Offset.zero);
|
|
|
|
}
|
|
|
|
|
|
|
|
@override
|
|
|
|
Path getOuterPath(Rect rect, {TextDirection? textDirection}) {
|
|
|
|
Path _getLeftTopPath(Rect rect) {
|
|
|
|
return Path()
|
|
|
|
..moveTo(rect.left, rect.bottom)
|
|
|
|
..lineTo(rect.left, rect.top)
|
|
|
|
..lineTo(rect.right, rect.top);
|
|
|
|
}
|
|
|
|
|
|
|
|
return _getLeftTopPath(rect)
|
|
|
|
..lineTo(
|
|
|
|
rect.right,
|
|
|
|
rect.bottom,
|
|
|
|
)
|
|
|
|
..lineTo(
|
|
|
|
rect.left,
|
|
|
|
rect.bottom,
|
|
|
|
)
|
|
|
|
..lineTo(
|
|
|
|
rect.left,
|
|
|
|
rect.top,
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
|
|
|
@override
|
|
|
|
void paint(Canvas canvas, Rect rect, {TextDirection? textDirection}) {
|
|
|
|
final width = rect.width;
|
|
|
|
final borderWidthSize = width / 2;
|
|
|
|
final height = rect.height;
|
|
|
|
final borderOffset = borderWidth / 2;
|
|
|
|
final newBorderLength = borderLength > cutOutSize / 2 + borderWidth * 2
|
|
|
|
? borderWidthSize / 2
|
|
|
|
: borderLength;
|
|
|
|
final newCutOutSize =
|
|
|
|
cutOutSize < width ? cutOutSize : width - borderOffset;
|
|
|
|
|
|
|
|
final backgroundPaint = Paint()
|
|
|
|
..color = overlayColor
|
|
|
|
..style = PaintingStyle.fill;
|
|
|
|
|
|
|
|
final borderPaint = Paint()
|
|
|
|
..color = borderColor
|
|
|
|
..style = PaintingStyle.stroke
|
|
|
|
..strokeWidth = borderWidth;
|
|
|
|
|
|
|
|
final boxPaint = Paint()
|
|
|
|
..color = borderColor
|
|
|
|
..style = PaintingStyle.fill
|
|
|
|
..blendMode = BlendMode.dstOut;
|
|
|
|
|
|
|
|
final cutOutRect = Rect.fromLTWH(
|
|
|
|
rect.left + width / 2 - newCutOutSize / 2 + borderOffset,
|
|
|
|
rect.top + height / 2 - newCutOutSize / 2 + borderOffset,
|
|
|
|
newCutOutSize - borderOffset * 2,
|
|
|
|
newCutOutSize - borderOffset * 2,
|
|
|
|
);
|
|
|
|
|
|
|
|
canvas
|
|
|
|
..saveLayer(
|
|
|
|
rect,
|
|
|
|
backgroundPaint,
|
|
|
|
)
|
|
|
|
..drawRect(
|
|
|
|
rect,
|
|
|
|
backgroundPaint,
|
|
|
|
)
|
|
|
|
// Draw top right corner
|
|
|
|
..drawRRect(
|
|
|
|
RRect.fromLTRBAndCorners(
|
|
|
|
cutOutRect.right - newBorderLength,
|
|
|
|
cutOutRect.top,
|
|
|
|
cutOutRect.right,
|
|
|
|
cutOutRect.top + newBorderLength,
|
|
|
|
topRight: Radius.circular(borderRadius),
|
|
|
|
),
|
|
|
|
borderPaint,
|
|
|
|
)
|
|
|
|
// Draw top left corner
|
|
|
|
..drawRRect(
|
|
|
|
RRect.fromLTRBAndCorners(
|
|
|
|
cutOutRect.left,
|
|
|
|
cutOutRect.top,
|
|
|
|
cutOutRect.left + newBorderLength,
|
|
|
|
cutOutRect.top + newBorderLength,
|
|
|
|
topLeft: Radius.circular(borderRadius),
|
|
|
|
),
|
|
|
|
borderPaint,
|
|
|
|
)
|
|
|
|
// Draw bottom right corner
|
|
|
|
..drawRRect(
|
|
|
|
RRect.fromLTRBAndCorners(
|
|
|
|
cutOutRect.right - newBorderLength,
|
|
|
|
cutOutRect.bottom - newBorderLength,
|
|
|
|
cutOutRect.right,
|
|
|
|
cutOutRect.bottom,
|
|
|
|
bottomRight: Radius.circular(borderRadius),
|
|
|
|
),
|
|
|
|
borderPaint,
|
|
|
|
)
|
|
|
|
// Draw bottom left corner
|
|
|
|
..drawRRect(
|
|
|
|
RRect.fromLTRBAndCorners(
|
|
|
|
cutOutRect.left,
|
|
|
|
cutOutRect.bottom - newBorderLength,
|
|
|
|
cutOutRect.left + newBorderLength,
|
|
|
|
cutOutRect.bottom,
|
|
|
|
bottomLeft: Radius.circular(borderRadius),
|
|
|
|
),
|
|
|
|
borderPaint,
|
|
|
|
)
|
|
|
|
..drawRRect(
|
|
|
|
RRect.fromRectAndRadius(
|
|
|
|
cutOutRect,
|
|
|
|
Radius.circular(borderRadius),
|
|
|
|
),
|
|
|
|
boxPaint,
|
|
|
|
)
|
|
|
|
..restore();
|
|
|
|
}
|
|
|
|
|
|
|
|
@override
|
|
|
|
ShapeBorder scale(double t) {
|
|
|
|
return ScannerOverlay(
|
|
|
|
borderColor: borderColor,
|
|
|
|
borderWidth: borderWidth,
|
|
|
|
overlayColor: overlayColor,
|
|
|
|
);
|
|
|
|
}
|
|
|
|
}
|