Flutter截图功能实现
我们可以使用GestureDetector
记录触摸,使用CustomPaint
在屏幕上绘制线条从而实现签名功能
参考步骤
- 使用
RenderBox.globalToLocal
将GestureDetector.onPanUpdate
提供的DragUpdateDetails
转换为相对坐标 - 使用
GestureDetector.onPanEnd
手势处理程序记录笔画之间的中断。 - Mutating the same
List
won't automatically trigger a repaint because theCustomPainter
constructor arguments are the same. You can trigger a repaint by creating a newList
each time a new point is provided. - 改变相同的
List
不会自动触发重绘,因为CustomPainter
构造函数参数是相同的。每次提供新点时,您都可以通过创建一个新的“列表”来触发重绘。 - 使用
Canvas.drawLine
在签名的每个记录点之间画一条线。
参考代码
import 'package:flutter/material.dart';
class SignaturePainter extends CustomPainter {
SignaturePainter(this.points);
final List<Offset> points;
void paint(Canvas canvas, Size size) {
Paint paint = new Paint()
..color = Colors.black
..strokeCap = StrokeCap.round
..strokeWidth = 5.0;
for (int i = 0; i < points.length - 1; i++) {
if (points[i] != null && points[i + 1] != null)
canvas.drawLine(points[i], points[i + 1], paint);
}
}
bool shouldRepaint(SignaturePainter other) => other.points != points;
}
class Signature extends StatefulWidget {
SignatureState createState() => new SignatureState();
}
class SignatureState extends State<Signature> {
List<Offset> _points = <Offset>[];
Widget build(BuildContext context) {
return new Stack(
children: [
GestureDetector(
onPanUpdate: (DragUpdateDetails details) {
RenderBox referenceBox = context.findRenderObject();
Offset localPosition =
referenceBox.globalToLocal(details.globalPosition);
setState(() {
_points = new List.from(_points)..add(localPosition);
});
},
onPanEnd: (DragEndDetails details) => _points.add(null),
),
CustomPaint(painter: SignaturePainter(_points), size: Size.infinite),
],
);
}
}
class DemoApp extends StatelessWidget {
Widget build(BuildContext context) => new Scaffold(body: new Signature());
}
void main() => runApp(new MaterialApp(home: new DemoApp()));
签名参考文章
截图保存签名图层
使用RepaintBoundary
在State中实现如下代码
class _MyHomePageState extends State<MyHomePage> {
GlobalKey rootWidgetKey = GlobalKey();
...
@override
Widget build(BuildContext context) {
return RepaintBoundary(
key: rootWidgetKey,
child: Scaffold(
appBar: AppBar(
title: Text(widget.title),
),
body: Column(
.....
),
),
);
}
}
通过rootWidgetKey可以拿到RenderRepaintBoundary的引用,进来拿到内部组件的截图:
class _MyHomePageState extends State<MyHomePage> {
GlobalKey rootWidgetKey = GlobalKey();
Future<Uint8List> _capturePng() async {
try {
RenderRepaintBoundary boundary =
rootWidgetKey.currentContext.findRenderObject();
var image = await boundary.toImage(pixelRatio: 3.0);
ByteData byteData = await image.toByteData(format: ImageByteFormat.png);
Uint8List pngBytes = byteData.buffer.asUint8List();
return pngBytes;//这个对象就是图片数据
} catch (e) {
print(e);
}
return null;
}
...
}
表评论5330
表评论4594
表评论8598
表评论8332
叼茂SEO.bfbikes.com
看的我热血沸腾啊https://www.jiwenlaw.com/
想想你的文章写的特别好https://www.jiwenlaw.com/
想想你的文章写的特别好
不错不错,我喜欢看
看的我热血沸腾啊
叼茂SEO.bfbikes.com
叼茂SEO.bfbikes.com
怎么收藏这篇文章?
怎么收藏这篇文章?
想想你的文章写的特别好https://www.237fa.com/
看的我热血沸腾啊https://www.237fa.com/
看的我热血沸腾啊https://www.237fa.com/
想想你的文章写的特别好https://www.ea55.com/
不错不错,我喜欢看 https://www.ea55.com/
看的我热血沸腾啊https://www.ea55.com/
看的我热血沸腾啊www.jiwenlaw.com
不错不错,我喜欢看 www.jiwenlaw.com
兄弟写的非常好 https://www.cscnn.com/
龙妈传奇第一季:冒险之旅:https://501h.com/danzhiye/7625.html
龙妈传奇第一季:冒险之旅:https://501h.com/danzhiye/7625.html
传奇私服中杀人后为何会死亡两次,这一现象引人深思:https://501h.com/yuanshi/2024-10-17/42856.html
《不可说》大陆综艺高清在线免费观看:https://www.jgz518.com/xingkong/115309.html
《不可说》大陆综艺高清在线免费观看:https://www.jgz518.com/xingkong/115309.html
《一条狗的使命国语》剧情片高清在线免费观看:https://www.jgz518.com/xingkong/43334.html
《一条狗的使命国语》剧情片高清在线免费观看:https://www.jgz518.com/xingkong/43334.html
《魅力游戏第三季》泰国剧高清在线免费观看:https://www.jgz518.com/xingkong/143421.html
哈哈哈,写的太好了https://www.lawjida.com/
哈哈哈,写的太好了https://www.lawjida.com/
哈哈哈,写的太好了https://www.lawjida.com/
哈哈哈,写的太好了https://www.lawjida.com/
文字流畅如丝,语言优美动人,读来令人心旷神怡。
这是一篇佳作,无论是从内容、语言还是结构上,都堪称完美。
多语种文献的引用彰显学术包容性。
建议补充发展中国家案例,避免视角局限。
建议补充性能优化方案,增强实用性。
文章结构紧凑,层次分明,逻辑严密,让人一读即懂。