Flutter 颤振:使用RepaitBoundary拍摄剪辑小部件的屏幕截图
我想创建一个带有颤振的图像裁剪器,我尝试使用ClipPath制作裁剪器,并重新绘制边界以拍摄可见区域的快照重新绘制边界的问题是拍摄整个子窗口小部件的屏幕截图,而不仅仅是剪切区域 代码:Flutter 颤振:使用RepaitBoundary拍摄剪辑小部件的屏幕截图,flutter,dart,crop,Flutter,Dart,Crop,我想创建一个带有颤振的图像裁剪器,我尝试使用ClipPath制作裁剪器,并重新绘制边界以拍摄可见区域的快照重新绘制边界的问题是拍摄整个子窗口小部件的屏幕截图,而不仅仅是剪切区域 代码: 将'dart:ui'导入为ui; 导入“dart:键入的_数据”; 导入“package:flatter/rendering.dart”; 导入“包:flifter/services.dart”; 进口“包装:颤振/材料.省道”; 导入“包:矩阵手势检测器/矩阵手势检测器.dart”; typedef cropV
将'dart:ui'导入为ui;
导入“dart:键入的_数据”;
导入“package:flatter/rendering.dart”;
导入“包:flifter/services.dart”;
进口“包装:颤振/材料.省道”;
导入“包:矩阵手势检测器/矩阵手势检测器.dart”;
typedef cropValue=未来函数();
类微控制器{
作物价值;
无效处置(){
裁剪=空;
}
}
类CropInteractiveView扩展StatefulWidget{
最后一个孩子;
最后一个布尔允许旋转手势;
最终双季种植比例;
最终CropController CropController;
常数CropinterActiview(
{键,
@需要这个孩子,
这个.cropController,
this.allowrotationsignature=false,
this.cropIxelRatio=3.0})
:super(key:key);
@凌驾
_CropinterActiviewState createState()=>\u CropinterActiviewState();
}
类_CropinterActiviewState扩展状态{
最终ValueNotifier通知程序=ValueNotifier(Matrix4.identity());
静态GlobalKey repainkey=GlobalKey();
未来作物()异步{
渲染绘制边界重新绘制边界=
repaitKey.currentContext.FindEnderObject();
图像=
等待RepaitBoundary.toImage(像素比率:widget.crappixelRatio);
ByteData ByteData=等待image.toByteData(格式:ui.ImageByteFormat.png);
Uint8List pngBytes=byteData.buffer.asUint8List();
返回PNG字节;
}
@凌驾
void initState(){
super.initState();
CropController\u controller=widget.CropController;
如果(_controller!=null){
_controller.crop=crop;
}
}
@凌驾
小部件构建(构建上下文){
返回堆栈(
适合:StackFit.loose,
儿童:[
容器(
颜色:颜色。灰色,
),
填充物(
填充:常数边集。全部(20),
儿童:中心(
子:重新绘制边界(
键:重新绘制键,
孩子:克利帕斯(
裁剪器:CropClipper(),
孩子:矩阵手势检测器(
shouldRotate:widget.allowrotation手势,
OnMatrix更新:(矩阵,平移三角矩阵,
缩放三角矩阵,旋转三角矩阵){
设置状态(){
notifier.value=矩阵;
});
},
孩子:变换(
transform:notifier.value,
子:容器(
颜色:Colors.amberAccent,子项:widget.child)),
),
),
),
),
],
);
}
}
类CropClipper扩展了CustomClipper{
@凌驾
路径getClip(大小){
返回路径()
//…addRect(Rect.fromLTWH(0.0,0.0,size.width,size.height))
…addRect(Rect.fromCenter(
中心:偏移(尺寸.宽度/2,尺寸.高度/2),
宽度:200.0,
高度:300.0)
..fillType=PathFillType.evenOdd;
}
@凌驾
bool shouldReclip(CustomClipper oldClipper)=>true;
}
截图:
理想的结果不应该被白色区域包围
这种情况下是否有巡视
import 'dart:ui' as ui;
import 'dart:typed_data';
import 'package:flutter/rendering.dart';
import 'package:flutter/services.dart';
import 'package:flutter/material.dart';
import 'package:matrix_gesture_detector/matrix_gesture_detector.dart';
typedef cropValue = Future<Uint8List> Function();
class CropController {
cropValue crop;
void dispose() {
crop = null;
}
}
class CropInteractiveView extends StatefulWidget {
final Widget child;
final bool allowRotationGesture;
final double cropPixelRatio;
final CropController cropController;
const CropInteractiveView(
{Key key,
@required this.child,
this.cropController,
this.allowRotationGesture = false,
this.cropPixelRatio = 3.0})
: super(key: key);
@override
_CropInteractiveViewState createState() => _CropInteractiveViewState();
}
class _CropInteractiveViewState extends State<CropInteractiveView> {
final ValueNotifier<Matrix4> notifier = ValueNotifier(Matrix4.identity());
static GlobalKey repaintKey = GlobalKey();
Future<Uint8List> crop() async {
RenderRepaintBoundary repaintBoundary =
repaintKey.currentContext.findRenderObject();
ui.Image image =
await repaintBoundary.toImage(pixelRatio: widget.cropPixelRatio);
ByteData byteData = await image.toByteData(format: ui.ImageByteFormat.png);
Uint8List pngBytes = byteData.buffer.asUint8List();
return pngBytes;
}
@override
void initState() {
super.initState();
CropController _controller = widget.cropController;
if (_controller != null) {
_controller.crop = crop;
}
}
@override
Widget build(BuildContext context) {
return Stack(
fit: StackFit.loose,
children: [
Container(
color: Colors.grey,
),
Padding(
padding: const EdgeInsets.all(20),
child: Center(
child: RepaintBoundary(
key: repaintKey,
child: ClipPath(
clipper: CropClipper(),
child: MatrixGestureDetector(
shouldRotate: widget.allowRotationGesture,
onMatrixUpdate: (matrix, translationDeltaMatrix,
scaleDeltaMatrix, rotationDeltaMatrix) {
setState(() {
notifier.value = matrix;
});
},
child: Transform(
transform: notifier.value,
child: Container(
color: Colors.amberAccent, child: widget.child))),
),
),
),
),
],
);
}
}
class CropClipper extends CustomClipper<Path> {
@override
Path getClip(Size size) {
return Path()
// ..addRect(Rect.fromLTWH(0.0, 0.0, size.width, size.height))
..addRect(Rect.fromCenter(
center: Offset(size.width / 2, size.height / 2),
width: 200.0,
height: 300.0))
..fillType = PathFillType.evenOdd;
}
@override
bool shouldReclip(CustomClipper<Path> oldClipper) => true;
}