Flutter 签名板 + 保存图片

Flutter 签名板 + 保存图片,第1张

不说多余的直接上代码
import 'dart:io';
import 'dart:typed_data';
import 'dart:ui';

import 'package:flutter/material.dart';
import 'package:flutter/rendering.dart';
import 'package:flutterappdz/resource.dart' as res;
import 'package:path_provider/path_provider.dart';
class SignPage extends StatefulWidget {
  const SignPage({Key? key}) : super(key: key);
  @override
  _SignPageState createState() => _SignPageState();
}

class _SignPageState extends State<SignPage> {


  GlobalKey key = GlobalKey();
  final GlobalKey _containerkey = GlobalKey();
  PointerEvent? _event;
  late List<Offset?> points = <Offset>[];
  Color selectColor = Colors.red;
  Uint8List? _postBytes;

  File? fileN;

  double y = 0;
  late double bottom;

  @override
  void initState() {
    super.initState();

    WidgetsBinding.instance!.addPostFrameCallback((timeStamp) {
      RenderBox box = _containerkey.currentContext!.findRenderObject() as RenderBox;
      Offset offset = box.localToGlobal(Offset.zero);
      y = offset.dy;
    });

  }


  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: const Text('签名'),
      ),
      body: Column(
        crossAxisAlignment: CrossAxisAlignment.start,
        children:  [
          const Padding(
            padding: EdgeInsets.symmetric(vertical: 20,horizontal: 16),
            child: Text('请在下方区域手写签名',style: TextStyle(fontSize: 16,fontWeight: FontWeight.w400),),
          ),
          Stack(
            children: [
              Container(
                width: double.infinity,
                color: Colors.white,
                child: Image.asset('assets/sign_image.png',fit: BoxFit.fill,),
              ),
              Positioned(

                left: 0,
                top: 0,
                bottom: 0,
                right: 0,
                child: RepaintBoundary(
                  key: key,
                  child: Stack(
                    children: [
                      Listener(
                        child: Container(
                          key: _containerkey,
                          alignment: Alignment.center,
                          color: Colors.transparent,
//                          width: double.infinity,
//                          height: double.infinity,
//                           child: Text(_event?.toString() ?? "",
//                               style: TextStyle(color: Colors.black)),
                        ),

                        onPointerDown: (PointerDownEvent event) {
                          setState(() {
                            _event = event;
                            points.add(_event?.localPosition ?? Offset.zero);
                          });
                        },
                        onPointerMove: (PointerMoveEvent event) {
                          setState(() {
                            _event = event;
                            if (_event != null){

                              RenderBox box = _containerkey.currentContext!.findRenderObject() as RenderBox;
                              Offset offset = box.localToGlobal(Offset.zero);
                              var dy = offset.dy;
                              var dbottom = box.size.height;


                              if (_event!.localPosition.dy < dbottom && _event!.localPosition.dy > 0){
                                points.add(_event?.localPosition ?? Offset.zero);
                              }
                            }

                          });
                        },
                        onPointerUp: (PointerUpEvent event) {
                          setState(() {
                            _event = event;
                            points.add(Offset.zero);
                          });
                        },
                      ),
                      Positioned(
                        left: (_event != null ? _event?.position.dx ?? 0 : 0),
                        top:  (_event != null ? (_event?.position.dy ?? 0) -
                          y : 0),
                        child: Container(
                          width: 1,
                          height: 1,
                          color: Colors.black,
                        ),),

                      CustomPaint(painter: SignaturePainter(points))


                    ],
                  ),



                )
              )
            ],
          ),

          Padding(
            padding: const EdgeInsets.only(top: 20),
            child: Row(
              children: [
                const SizedBox(
                  width: 24,
                ),
                Expanded(
                  child: OutlinedButton(
                    style: ButtonStyle(
                      padding: MaterialStateProperty.all(const EdgeInsets.symmetric(vertical: 10)),
                      side: MaterialStateProperty.all(const BorderSide(color: res.Colors.majorColor)),
                      shape: MaterialStateProperty.all(
                        RoundedRectangleBorder(
                          borderRadius: BorderRadius.circular(8),
                        ),
                      ),
                    ),
                    onPressed: () {

                      setState(() {
                        points = [];
                      });
                    },
                    child: const Text('重置'),
                  ),
                ),

                const SizedBox(
                  width: 10,
                ),
                Expanded(
                  child: ElevatedButton(
                    style: ButtonStyle(
                      padding: MaterialStateProperty.all(const EdgeInsets.symmetric(vertical: 10)),
                      side: MaterialStateProperty.all(const BorderSide(color: res.Colors.majorColor)),
                      shape: MaterialStateProperty.all(
                        RoundedRectangleBorder(
                          borderRadius: BorderRadius.circular(8),
                        ),
                      ),
                    ),
                    onPressed: () {
                      _saveSignPic();
                    },
                    child: const Text('确定'),
                  ),
                ),
                const SizedBox(
                  width: 24,
                ),
              ],
            ),
          ),
          if(fileN != null)

            Container(
              color: Colors.red,
              constraints: const BoxConstraints(
                maxHeight: 100,
                maxWidth: 100,
              ),

              child:  Image(image: FileImageEx(fileN!),),
            ),

          
        ],
      ),
    );
  }

  // 保存签名
  void _saveSignPic() async{
    
    RenderRepaintBoundary boundary = key.currentContext!.findRenderObject() as RenderRepaintBoundary;
    
    var image = await boundary.toImage(pixelRatio: 1);
    ByteData? byteData = await image.toByteData(format: ImageByteFormat.png);


    Directory dir = await getTemporaryDirectory();

    String path = dir.path +"/"+ 'sign.png';

    var file = await File(path).create(recursive: true);

    if(byteData != null){
      file.writeAsBytesSync(byteData.buffer.asInt8List(),flush: true);

      setState(() {
        _postBytes = byteData.buffer.asUint8List();
        fileN = file;
      });

    }
  }

}


class SignaturePainter extends CustomPainter {
  SignaturePainter(this.points);

  final List<Offset?> points;
  final Color paintColor = Colors.black;

  Paint myPaint = new Paint();

  void paint(Canvas canvas, Size size) {
    myPaint.strokeCap = StrokeCap.round;
    myPaint.strokeWidth = 5.0;
    for (int i = 0; i < points.length - 1; i++) {
      if (points[i] != null &&
        points[i + 1] != null &&
        points[i] != Offset.zero &&
        points[i + 1] != Offset.zero) {
        canvas.drawLine(points[i]!, points[i + 1]!, myPaint);
      }
    }
  }

  bool shouldRepaint(SignaturePainter other) => other.points != points;
}

// ignore: must_be_immutable
class FileImageEx extends FileImage {
  int? fileSize;
  FileImageEx(File file, { double scale = 1.0 })
    : assert(file != null),
      assert(scale != null),
      super(file, scale: scale) {
    fileSize = file.lengthSync();
  }

  @override
  bool operator ==(dynamic other) {
    if (other.runtimeType != runtimeType) {
      return false;
    }
    final FileImageEx typedOther = other;
    return file.path == typedOther.file.path
      && scale == typedOther.scale && fileSize == typedOther.fileSize;
  }
}

欢迎分享,转载请注明来源:内存溢出

原文地址:https://54852.com/web/994624.html

(0)
打赏 微信扫一扫微信扫一扫 支付宝扫一扫支付宝扫一扫
上一篇 2022-05-21
下一篇2022-05-21

发表评论

登录后才能评论

评论列表(0条)

    保存