import 'dart:ui'; import 'package:flutter/material.dart'; class CropperPainter extends CustomPainter { final Rect rect; final double gridOpacity; final int gridDivision; const CropperPainter({ required this.rect, required this.gridOpacity, required this.gridDivision, }); static const double handleLength = kMinInteractiveDimension / 3 - 4; static const double handleWidth = 3; static const double borderWidth = 1; static const double gridWidth = 1; static const cornerColor = Colors.white; static final borderColor = Colors.white.withOpacity(.5); static final gridColor = Colors.white.withOpacity(.5); @override void paint(Canvas canvas, Size size) { final cornerPaint = Paint() ..style = PaintingStyle.fill ..strokeCap = StrokeCap.round ..strokeWidth = handleWidth ..color = cornerColor; final gridPaint = Paint() ..style = PaintingStyle.stroke ..strokeWidth = gridWidth ..color = gridColor.withOpacity(gridColor.opacity * gridOpacity); final xLeft = rect.left; final yTop = rect.top; final xRight = rect.right; final yBottom = rect.bottom; final gridLeft = xLeft + borderWidth / 2; final gridRight = xRight - borderWidth / 2; final yStep = (yBottom - yTop) / gridDivision; for (var i = 1; i < gridDivision; i++) { canvas.drawLine( Offset(gridLeft, yTop + i * yStep), Offset(gridRight, yTop + i * yStep), gridPaint, ); } final gridTop = yTop + borderWidth / 2; final gridBottom = yBottom - borderWidth / 2; final xStep = (xRight - xLeft) / gridDivision; for (var i = 1; i < gridDivision; i++) { canvas.drawLine( Offset(xLeft + i * xStep, gridTop), Offset(xLeft + i * xStep, gridBottom), gridPaint, ); } canvas.drawPoints( PointMode.polygon, [ rect.topLeft.translate(0, handleLength), rect.topLeft, rect.topLeft.translate(handleLength, 0), ], cornerPaint); canvas.drawPoints( PointMode.polygon, [ rect.topRight.translate(-handleLength, 0), rect.topRight, rect.topRight.translate(0, handleLength), ], cornerPaint); canvas.drawPoints( PointMode.polygon, [ rect.bottomRight.translate(0, -handleLength), rect.bottomRight, rect.bottomRight.translate(-handleLength, 0), ], cornerPaint); canvas.drawPoints( PointMode.polygon, [ rect.bottomLeft.translate(handleLength, 0), rect.bottomLeft, rect.bottomLeft.translate(0, -handleLength), ], cornerPaint); } @override bool shouldRepaint(covariant CustomPainter oldDelegate) => true; } class ScrimPainter extends CustomPainter { final Path excludePath; final double opacity; const ScrimPainter({ required this.excludePath, required this.opacity, }); static const double borderWidth = 1; static const scrimColor = Colors.black; @override void paint(Canvas canvas, Size size) { final scrimPaint = Paint() ..style = PaintingStyle.fill ..color = scrimColor.withOpacity(opacity); final outside = Path() ..addRect(Rect.fromLTWH(0, 0, size.width, size.height).inflate(.5)) ..close(); canvas.drawPath(Path.combine(PathOperation.difference, outside, excludePath), scrimPaint); } @override bool shouldRepaint(covariant CustomPainter oldDelegate) => true; }