Flutter中实现签名功能

我们可以使用GestureDetector记录触摸,使用CustomPaint 在屏幕上绘制线条从而实现签名功能

参考步骤

  • 使用 RenderBox.globalToLocal 将  GestureDetector.onPanUpdate提供的DragUpdateDetails  转换为相对坐标
  • 使用GestureDetector.onPanEnd 手势处理程序记录笔画之间的中断。
  • Mutating the same List won't automatically trigger a repaint because the CustomPainter constructor arguments are the same. You can trigger a repaint by creating a new List 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;
  }
  ...
}

复制代码

截图功能参考文章

猜你喜欢

转载自juejin.im/post/7101186782498127903