Saltar al contenido

¿Cómo agregar Signature en Flutter?

Buscamos por todo internet para traerte la solución a tu dilema, en caso de alguna difcultad déjanos la pregunta y responderemos con mucho gusto, porque estamos para servirte.

Solución:

Signature Class necesita ser modificado para responder a VerticalDrag , Lo renombré a Signature1

ahora el pad del área de la firma no debería desplazarse, puede verificar el código completo a continuación, ya que se comporta. Descubrirá que el área de Firma ya no se desplaza con el SingleChildScrollView.

import 'package:flutter/material.dart';
import 'package:flutter/rendering.dart';
import 'dart:async';
import 'dart:ui' as ui;

void main() => runApp(MyApp());

class MyApp extends StatelessWidget 
  // This widget is the root of your application.
  @override
  Widget build(BuildContext context) 
    return MaterialApp(
      title: 'Flutter Demo',
      theme: ThemeData(
        primarySwatch: Colors.blue,
      ),
      home: MyHomePage(title: 'Flutter Demo Home Page'),
    );
  


class MyHomePage extends StatefulWidget 
  MyHomePage(Key key, this.title) : super(key: key);

  final String title;

  @override
  _MyHomePageState createState() => _MyHomePageState();


class _MyHomePageState extends State 
  var color = Colors.black;
  var strokeWidth = 3.0;
  final _sign = GlobalKey();

  @override
  Widget build(BuildContext context) 
    return Scaffold(
      appBar: AppBar(
        title: Text(widget.title),
      ),
      body:
           SingleChildScrollView(
             child: Column(
               children: [
                 _showCategory(),
                 SizedBox(height: 15),
                 _showCategory(),
                 SizedBox(height: 15),
                 _showCategory(),
                 SizedBox(height: 15),
                 _showCategory(),
                 SizedBox(height: 15),
                 _showCategory(),
                 _showCategory(),
                 SizedBox(height: 15),
                 _showCategory(),
                 SizedBox(height: 15),
                 _showCategory(),
                 SizedBox(height: 15),
                 _showCategory(),
                 SizedBox(height: 15),
                 _showCategory(),
                 _showSignaturePad()
               ],
             ),
           )

      ,
    );
  

  Widget _showCategory() 
    return TextField(
        onTap: () 
          FocusScope.of(context).requestFocus(FocusNode());
        ,
        style: TextStyle(fontSize: 12.0, height: 1.0),
        decoration: InputDecoration(hintText: "TextView"));
  

  Widget _showSignaturePad() 
    return Container(
      width: double.infinity,
      height: 200,
      child: Padding(
        padding: const EdgeInsets.all(8.0),
        child: Container(
          height: 200,
          //color: Colors.red,
          child: Signature1(
            color: color,
            key: _sign,
            strokeWidth: strokeWidth,
          ),
        ),
      ),
      color: Colors.grey.shade300,
    );
  

class Signature1 extends StatefulWidget 
  final Color color;
  final double strokeWidth;
  final CustomPainter backgroundPainter;
  final Function onSign;

  Signature1(
    this.color = Colors.black,
    this.strokeWidth = 5.0,
    this.backgroundPainter,
    this.onSign,
    Key key,
  ) : super(key: key);

  Signature1State createState() => Signature1State();

  static Signature1State of(BuildContext context) 
    return context.findAncestorStateOfType();
  


class _SignaturePainter extends CustomPainter 
  Size _lastSize;
  final double strokeWidth;
  final List points;
  final Color strokeColor;
  Paint _linePaint;

  _SignaturePainter(@required this.points, @required this.strokeColor, @required this.strokeWidth) 
    _linePaint = Paint()
      ..color = strokeColor
      ..strokeWidth = strokeWidth
      ..strokeCap = StrokeCap.round;
  

  @override
  void paint(Canvas canvas, Size size) 
    _lastSize = size;
    for (int i = 0; i < points.length - 1; i++) 
      if (points[i] != null && points[i + 1] != null) canvas.drawLine(points[i], points[i + 1], _linePaint);
    
  

  @override
  bool shouldRepaint(_SignaturePainter other) => other.points != points;


class Signature1State extends State 
  List _points = [];
  _SignaturePainter _painter;
  Size _lastSize;

  Signature1State();

  void _onDragStart(DragStartDetails details)
    RenderBox referenceBox = context.findRenderObject();
    Offset localPostion = referenceBox.globalToLocal(details.globalPosition);
    setState(() 
      _points = List.from(_points)
        ..add(localPostion)
        ..add(localPostion);
    );
  
  void _onDragUpdate (DragUpdateDetails details) 
    RenderBox referenceBox = context.findRenderObject();
    Offset localPosition = referenceBox.globalToLocal(details.globalPosition);

    setState(() 
      _points = List.from(_points)..add(localPosition);
      if (widget.onSign != null) 
        widget.onSign();
      
    );
  
  void _onDragEnd (DragEndDetails details) => _points.add(null);

  @override
  Widget build(BuildContext context) 
    WidgetsBinding.instance.addPostFrameCallback((_) => afterFirstLayout(context));
    _painter = _SignaturePainter(points: _points, strokeColor: widget.color, strokeWidth: widget.strokeWidth);
    return ClipRect(
      child: CustomPaint(
        painter: widget.backgroundPainter,
        foregroundPainter: _painter,
        child: GestureDetector(

          onVerticalDragStart: _onDragStart,
          onVerticalDragUpdate: _onDragUpdate,
          onVerticalDragEnd: _onDragEnd,

          onPanStart: _onDragStart,
          onPanUpdate: _onDragUpdate,
          onPanEnd: _onDragEnd
        ),
      ),
    );
  

  Future getData() 
    var recorder = ui.PictureRecorder();
    var origin = Offset(0.0, 0.0);
    var paintBounds = Rect.fromPoints(_lastSize.topLeft(origin), _lastSize.bottomRight(origin));
    var canvas = Canvas(recorder, paintBounds);
    if(widget.backgroundPainter != null) 
      widget.backgroundPainter.paint(canvas, _lastSize);
    
    _painter.paint(canvas, _lastSize);
    var picture = recorder.endRecording();
    return picture.toImage(_lastSize.width.round(), _lastSize.height.round());
  

  void clear() 
    setState(() 
      _points = [];
    );
  

  bool get hasPoints => _points.length > 0;

  List get points => _points;

  afterFirstLayout(BuildContext context) 
    _lastSize = context.size;
  

necesita crear un CustomGestureDetector.

Consulte esta versión actualizada de Signature que te acabo de cambiar:


    import 'dart:async';
    import 'dart:ui' as ui;

    import 'package:flutter/gestures.dart';
    import 'package:flutter/material.dart';

    class Signature extends StatefulWidget 
      final Color color;
      final double strokeWidth;
      final CustomPainter backgroundPainter;
      final Function onSign;

      Signature(
        this.color = Colors.black,
        this.strokeWidth = 5.0,
        this.backgroundPainter,
        this.onSign,
        Key key,
      ) : super(key: key);

      SignatureState createState() => SignatureState();

      static SignatureState of(BuildContext context) 
        return context.findAncestorStateOfType();
      
    

    class CustomPanGestureRecognizer extends OneSequenceGestureRecognizer 
      final Function onPanStart;
      final Function onPanUpdate;
      final Function onPanEnd;

      CustomPanGestureRecognizer(@required this.onPanStart, @required this.onPanUpdate, @required this.onPanEnd);

      @override
      void addPointer(PointerEvent event) 
        onPanStart(event.position);
        startTrackingPointer(event.pointer);
        resolve(GestureDisposition.accepted);
      

      @override
      void handleEvent(PointerEvent event) 
        if (event is PointerMoveEvent) 
          onPanUpdate(event.position);
        
        if (event is PointerUpEvent) 
          onPanEnd(event.position);
          stopTrackingPointer(event.pointer);
        
      

      @override
      String get debugDescription => 'customPan';

      @override
      void didStopTrackingLastPointer(int pointer) 
    

    class _SignaturePainter extends CustomPainter 
      Size _lastSize;
      final double strokeWidth;
      final List points;
      final Color strokeColor;
      Paint _linePaint;

      _SignaturePainter(@required this.points, @required this.strokeColor, @required this.strokeWidth) 
        _linePaint = Paint()
          ..color = strokeColor
          ..strokeWidth = strokeWidth
          ..strokeCap = StrokeCap.round;
      

      @override
      void paint(Canvas canvas, Size size) 
        _lastSize = size;
        for (int i = 0; i < points.length - 1; i++) 
          if (points[i] != null && points[i + 1] != null) canvas.drawLine(points[i], points[i + 1], _linePaint);
        
      

      @override
      bool shouldRepaint(_SignaturePainter other) => other.points != points;
    

    class SignatureState extends State 
      List _points = [];
      _SignaturePainter _painter;
      Size _lastSize;

      SignatureState();

      @override
      Widget build(BuildContext context) 
        WidgetsBinding.instance.addPostFrameCallback((_) => afterFirstLayout(context));
        _painter = _SignaturePainter(points: _points, strokeColor: widget.color, strokeWidth: widget.strokeWidth);
        return ClipRect(
          child: CustomPaint(
            painter: widget.backgroundPainter,
            foregroundPainter: _painter,
            child: RawGestureDetector(
              gestures: 
                CustomPanGestureRecognizer: GestureRecognizerFactoryWithHandlers(
                  () => CustomPanGestureRecognizer(
                    onPanStart: (position) 
                      RenderBox referenceBox = context.findRenderObject();
                      Offset localPostion = referenceBox.globalToLocal(position);
                      setState(() 
                        _points = List.from(_points)..add(localPostion)..add(localPostion);
                      );
                      return true;
                    ,
                    onPanUpdate: (position) 
                      RenderBox referenceBox = context.findRenderObject();
                      Offset localPosition = referenceBox.globalToLocal(position);

                      setState(() 
                        _points = List.from(_points)..add(localPosition);
                        if (widget.onSign != null) 
                          widget.onSign();
                        
                      );
                    ,
                    onPanEnd: (position) 
                      _points.add(null);
                    ,
                  ),
                  (CustomPanGestureRecognizer instance) ,
                ),
              ,
            ),
          ),
        );
      

      Future getData() 
        var recorder = ui.PictureRecorder();
        var origin = Offset(0.0, 0.0);
        var paintBounds = Rect.fromPoints(_lastSize.topLeft(origin), _lastSize.bottomRight(origin));
        var canvas = Canvas(recorder, paintBounds);
        if (widget.backgroundPainter != null) 
          widget.backgroundPainter.paint(canvas, _lastSize);
        
        _painter.paint(canvas, _lastSize);
        var picture = recorder.endRecording();
        return picture.toImage(_lastSize.width.round(), _lastSize.height.round());
      

      void clear() 
        setState(() 
          _points = [];
        );
      

      bool get hasPoints => _points.length > 0;

      List get points => _points;

      afterFirstLayout(BuildContext context) 
        _lastSize = context.size;
      
    


Atención especial a CustomPanGestureRecognizer

Puedes leer más en:

Desambiguación de gestos

Esto sucede porque el gesto de SingleChildScrollView anula el gesto de su widget de firma como el SingleChildScrollView es el padre. Hay pocas formas de resolverlo como en las otras respuestas de este hilo. Pero el más sencillo es utilizar el paquete existente. Simplemente puede usar el siguiente widget Flutter SignaturePad de Syncfusion que estoy usando ahora para mi aplicación. Este widget funcionará en plataformas web, iOS y Android.

Paquete: https://pub.dev/packages/syncfusion_flutter_signaturepad

Funciones: https://www.syncfusion.com/flutter-widgets/flutter-signaturepad

Documentación: https://help.syncfusion.com/flutter/signaturepad/getting-started

Nos puedes añadir valor a nuestra información colaborando tu veteranía en las crónicas.

¡Haz clic para puntuar esta entrada!
(Votos: 0 Promedio: 0)



Utiliza Nuestro Buscador

Deja una respuesta

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *