我有一个图像(蓝色矩形)。我想通过路径(红色三角形)剪切图像的一部分,并创建一个较小的小部件(绿色矩形)来显示图像的这一部分,并且其大小等于剪切路径的边界。我怎样才能在 Flutter 中做到这一点?
我尝试使用
ClipPath
和CustomClipper<Path>
,但我只能创建具有图像大小的小部件。
由于您没有提供任何代码,我假设您想要基于当前子级的小部件。
如果是,您可以尝试
IntrinsicWidth
和IntrinsicHeight
小部件。
https://api.flutter.dev/flutter/widgets/IntrinsicWidth-class.html
IntrinsicWidgth
:
创建一个小部件,将其子级的大小调整为子级的固有宽度。
这个类很有用,例如,当无限宽度可用时 你想要一个否则会尝试扩展的孩子 无限地将自身调整为更合理的宽度。
使用此小部件,子级将根据内在大小进行渲染。
我找到了这个解决方案:
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;
}
这是一个不使用
CustomClipper
的解决方案。
class TileWidget extends StatelessWidget {
final int left;
final int top;
final int width;
final int height;
final ui.Image image;
const TileWidget(this.image,
this.left, this.top, this.width, this.height,
{super.key});
@override
Widget build(BuildContext context) {
return CustomPaint(
size: Size(width.toDouble(), height.toDouble()),
painter: _SquarePainter(image, left, top, width, height));
}
}
class _SquarePainter extends CustomPainter {
final int left;
final int top;
final int width;
final int height;
final ui.Image tileset;
_SquarePainter(this.tileset, this.left, this.top, this.width, this.height);
@override
void paint(Canvas canvas, Size size) {
canvas.drawAtlas(
tileset,
[
RSTransform.fromComponents(
rotation: 0.0,
scale: 1.0,
anchorX: 0.0,
anchorY: 0.0,
translateX: 0.0,
translateY: 0.0)
],
[
Rect.fromLTWH(
left.toDouble(),
top.toDouble(),
width.toDouble(),
height.toDouble(),
)
],
[],
BlendMode.src,
null,
Paint(),
);
}
@override
bool shouldRepaint(_SquarePainter oldDelegate) => false;
@override
bool shouldRebuildSemantics(_SquarePainter oldDelegate) => false;
}