I have an image (blue rect). I want to cut a part of the image by path (red triangle) and create a smaller widget (green rect) that shows this part of the image and has size which equals bounds of cutting path. How can I do it in Flutter?
I tried to use ClipPath
and CustomClipper<Path>
, but I was able to create only widget which has size of the image.
I found this solution:
import 'dart:typed_data';
import 'dart:ui' as ui;
import 'package:flutter/material.dart';
class MyWidget extends StatelessWidget {
final ui.Image _uiImage;
final Path _clipPath;
const MyWidget({
Key? key,
required ui.Image uiImage,
required Path clipPath,
}) : _uiImage = uiImage,
_clipPath = clipPath,
super(key: key);
@override
Widget build(BuildContext context) {
final bounds = _clipPath.getBounds();
final translateM = Float64List.fromList([
1, 0, 0, 0,
0, 1, 0, 0,
0, 0, 1, 0,
-bounds.left, -bounds.top, 0, 1
]);
final localClipPath = _clipPath.transform(translateM);
return ClipPath(
clipper: _MyClipper(localClipPath),
child: CustomPaint(
painter: _MyPainter(_uiImage, bounds),
child: SizedBox(
width: bounds.width,
height: bounds.height,
),
),
);
}
}
class _MyClipper extends CustomClipper<Path> {
final Path _clipPath;
_MyClipper(this._clipPath);
@override
Path getClip(Size size) => _clipPath;
@override
bool shouldReclip(covariant CustomClipper<Path> oldClipper) => true;
}
class _MyPainter extends CustomPainter {
final ui.Image _uiImage;
final Rect _bounds;
final _paint = Paint();
_MyPainter(this._uiImage, this._bounds);
@override
void paint(Canvas canvas, Size size) {
canvas.drawAtlas(
_uiImage,
[
RSTransform.fromComponents(
rotation: 0.0,
scale: 1.0,
// Center of the sprite relative to its rect
anchorX: _bounds.width / 2,
anchorY: _bounds.height / 2,
// Location at which to draw the center of the sprite
translateX: _bounds.width / 2,
translateY: _bounds.height / 2,
)
],
[_bounds],
null,
null,
null,
_paint,
);
}
@override
bool shouldRepaint(_MyPainter oldDelegate) => false;
}