使用Xamarin Forms(PCL)捕获手绘签名

问题描述 投票:-1回答:2

我试图找出如何向用户询问签名区域,以便他们可以用手指签名,然后将该签名保存到文件中,我就到了死胡同。我看过Kimserey的博客,CrossGraphics库和SkiaSharp,但这些似乎都是围绕通过代码制作图像而不是用户用手指画画。该解决方案需要在pcl项目中使用,并将部署到Android,iOS和UWP。有没有人有想法?

xamarin
2个回答
1
投票

SignaturePadDemoPage.xaml

<?xml version="1.0" encoding="utf-8"?>
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms" 
BackgroundColor="Gray" 
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml" 
xmlns:local="clr-
namespace:SignaturePadDemo;assembly:SignaturePadDemo" 
x:Class="SignaturePadDemo.SignaturePadDemoPage">

<Grid HorizontalOptions="FillAndExpand" VerticalOptions="FillAndExpand" Padding="30">
    <Grid.RowDefinitions>
        <RowDefinition Height="Auto"/>
        <RowDefinition Height="*"/>
        <RowDefinition Height="Auto"/>
    </Grid.RowDefinitions>
    <Label Text="SignaturePad Demo" Grid.Row="0" VerticalOptions="Start" HorizontalOptions="Center" TextColor="White" FontSize="25"/>
    <local:ImageWithTouch x:Name="imgSiganturePad" Grid.Row="1" VerticalOptions="FillAndExpand" HorizontalOptions="FillAndExpand" BackgroundColor="White" CurrentLineColor="Fuchsia"/>
    <Grid Grid.Row="2" VerticalOptions="EndAndExpand">
    <Grid.RowDefinitions>
        <RowDefinition Height="Auto"/>
        <RowDefinition Height="Auto"/>
        <RowDefinition Height="Auto"/>
            </Grid.RowDefinitions>

    <Button x:Name="btnSave" Text="Save the Image" Grid.Row="0" HorizontalOptions="FillAndExpand" TextColor="Blue" BackgroundColor="White" Clicked="btnSaveImage_Click"/>
    <Button x:Name="btnSee" Text="See the Image" Grid.Row="1" HorizontalOptions="FillAndExpand" TextColor="Blue" BackgroundColor="White" Clicked="btnSeeImage_Click"/>
    <Button x:Name="btnClear" Text="Clear" Grid.Row="2" HorizontalOptions="FillAndExpand" TextColor="Blue" BackgroundColor="White" Clicked="btnClear_Click"/>
    </Grid>

    </Grid>

SignaturePadDemoPage.xaml.cs

using System;
using Xamarin.Forms;

namespace SignaturePadDemo
{
  public partial class SignaturePadDemoPage : ContentPage
   {
    public SignaturePadDemoPage()
    {
        InitializeComponent();
    }

    private void btnSaveImage_Click(object sender, EventArgs e)
    {

        var imgPath = DependencyService.Get<ISign>().Sign();
        imgSiganturePad.SavedImagePath = imgPath;
        btnSee.IsEnabled = true;
        DisplayAlert("SignaturePadDemo", "Your siganture saved succesfully", "Ok");

    }
    private void btnSeeImage_Click(object sender, EventArgs e)
    {
        Navigation.PushModalAsync(new 
        SignatureDetailPage(imgSiganturePad.SavedImagePath));
        imgSiganturePad.ClearPath = !imgSiganturePad.ClearPath;
    }
    private void btnClear_Click(object sender, EventArgs e)
    {
        imgSiganturePad.ClearPath = !imgSiganturePad.ClearPath;
        DisplayAlert("SignaturePadDemo", "Siganture was clear", "Ok");
      }
   }
 }

图像的自定义渲染器

PCL:

ImageWithTouch.cs

using System;
using Xamarin.Forms;

namespace SignaturePadDemo
 {
 public class ImageWithTouch : Image
 {
    public static readonly BindableProperty CurrentLineColorProperty =
        BindableProperty.Create((ImageWithTouch w) => w.CurrentLineColor, Color.Default);

    public static readonly BindableProperty CurrentLineWidthProperty =
        BindableProperty.Create((ImageWithTouch w) => w.CurrentLineWidth, 1);

    public static readonly BindableProperty CurrentImageProperty =
        BindableProperty.Create((ImageWithTouch w) => w.CurrentImagePath, "");

    public static readonly BindableProperty ClearImagePathProperty =
        BindableProperty.Create((ImageWithTouch w) => w.ClearPath, false);

    public static readonly BindableProperty SavedImagePathProperty =
        BindableProperty.Create((ImageWithTouch w) => w.SavedImagePath, "");

    public Color CurrentLineColor
    {
        get
        {
            return (Color)GetValue(CurrentLineColorProperty);
        }
        set
        {
            SetValue(CurrentLineColorProperty, value);
        }
    }

    public int CurrentLineWidth
    {
        get
        {
            return (int)GetValue(CurrentLineWidthProperty);
        }
        set
        {
            SetValue(CurrentLineWidthProperty, value);
        }
    }

    public string CurrentImagePath
    {
        get
        {
            return (string)GetValue(CurrentImageProperty);
        }
        set
        {
            SetValue(CurrentImageProperty, value);
        }
    }

    public bool ClearPath
    {
        get
        {
            return (bool)GetValue(ClearImagePathProperty);
        }
        set
        {
            SetValue(ClearImagePathProperty, value);
        }
    }

    public string SavedImagePath
    {
        get
        {
            return (string)GetValue(SavedImagePathProperty);
        }
        set
        {
            SetValue(SavedImagePathProperty, value);
        }
       }
   }
}

XA Marin.Android:

ImageWithTouchRenderer.cs

using System;
using System.ComponentModel;
using Xamarin.Forms.Platform.Android;
using Xamarin.Forms;
using Android.Graphics;
using Java.IO;
using System.IO;
using SignaturePadDemo;
using SignaturePadDemo.Droid;

 [assembly: ExportRenderer(typeof(ImageWithTouch), 

类型(带触摸渲染器的图像))]

 namespace SignaturePadDemo.Droid
 {
   public class ImageWithTouchRenderer : ViewRenderer<ImageWithTouch, DrawView>
   {
    protected override void OnElementChanged(ElementChangedEventArgs<ImageWithTouch> e)
    {
        base.OnElementChanged(e);

        if (e.OldElement == null)
        {
            SetNativeControl(new DrawView(Context));
        }
    }

    protected override void OnElementPropertyChanged(object sender, PropertyChangedEventArgs e)
    {
        base.OnElementPropertyChanged(sender, e);

        if (e.PropertyName == ImageWithTouch.ClearImagePathProperty.PropertyName)
        {
            Control.Clear();
        }
        else if (e.PropertyName == ImageWithTouch.SavedImagePathProperty.PropertyName)
        {
            Bitmap curDrawingImage = Control.GetImageFromView();

            Byte[] imgBytes = ImageHelper.BitmapToBytes(curDrawingImage);
            Java.IO.File f = new Java.IO.File(Element.SavedImagePath);

            f.CreateNewFile();

            FileOutputStream fo = new FileOutputStream(f);
            fo.Write(imgBytes);

            fo.Close();
        }
        else
        {
            UpdateControl(true);
        }
    }

    private void UpdateControl(bool bDisplayFlag)
    {
        Control.CurrentLineColor = Element.CurrentLineColor.ToAndroid();
        Control.PenWidth = Element.CurrentLineWidth * 3;
        Control.ImageFilePath = Element.CurrentImagePath;

        if (bDisplayFlag)
        {
            Control.LoadImageFromFile();
            Control.Invalidate();
        }
      }
   }
}

Xamarin.iOS:

ImageWithTouchRenderer.cs

using System.Drawing;
using Xamarin.Forms.Platform.iOS;
using Xamarin.Forms;
using System.ComponentModel;
using UIKit;
using Foundation;
using SignaturePadDemo;
using SignaturePadDemo.iOS;

[assembly: ExportRenderer(typeof(ImageWithTouch), typeof(ImageWithTouchRenderer))]

namespace SignaturePadDemo.iOS
{
  public class ImageWithTouchRenderer : ViewRenderer<ImageWithTouch, DrawView>
   {
    protected override void OnElementChanged(ElementChangedEventArgs<ImageWithTouch> e)
    {
        base.OnElementChanged(e);

        SetNativeControl(new DrawView(RectangleF.Empty));
    }

    protected override void OnElementPropertyChanged(object sender, PropertyChangedEventArgs e)
    {
        base.OnElementPropertyChanged(sender, e);

        if (e.PropertyName == ImageWithTouch.ClearImagePathProperty.PropertyName)
        {
            Control.Clear();
        }
        else if (e.PropertyName == ImageWithTouch.SavedImagePathProperty.PropertyName)
        {
            UIImage curDrawingImage = Control.GetImageFromView();
            NSData data = curDrawingImage.AsJPEG();
            NSError error = new NSError();
            bool bSuccess = data.Save(Element.SavedImagePath, true, out error);
        }
        else
        {
            UpdateControl(e.PropertyName == ImageWithTouch.CurrentLineColorProperty.PropertyName ||
                e.PropertyName == ImageWithTouch.CurrentImageProperty.PropertyName ||
                e.PropertyName == ImageWithTouch.CurrentLineWidthProperty.PropertyName);
        }
    }

    private void UpdateControl(bool bDisplayFlag)
    {
        Control.CurrentLineColor = Element.CurrentLineColor.ToUIColor();
        Control.PenWidth = Element.CurrentLineWidth;

        if (Control.ImageFilePath != Element.CurrentImagePath)
        {
            Control.ImageFilePath = Element.CurrentImagePath;
            Control.LoadImageFromFile();
        }

        if (bDisplayFlag)
        {
            Control.SetNeedsDisplay();
        }
      }
   }
 }

DependencyService获取在本地存储中存储Image的路径

ISign.cs

 using System;
 namespace SignaturePadDemo
 {
   public interface ISign
    {
      string Sign();
   }
 }

XA Marin.Android:

ISignService.cs

using System;
using SignaturePadDemo.Droid;
using Xamarin.Forms;

[assembly: Dependency(typeof(ISignService))]
namespace SignaturePadDemo.Droid
{
 public class ISignService : ISign
  {
    public string Sign()
    {
        string savedFileName = Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments) + "/temp_" + DateTime.Now.ToString("yyyy_mm_dd_hh_mm_ss") + ".jpg";
        return savedFileName;
     }
  }
}

DrawView.cs

  using Android.Views;
  using Android.Graphics;
  using Android.Content;
  using System;

 namespace SignaturePadDemo.Droid
 {
   public class DrawView : View
   {
    public DrawView(Context context)
        : base(context)
    {
        Start();
    }

    public Color CurrentLineColor { get; set; }
    public String ImageFilePath { get; set; }

    public float PenWidth { get; set; }

    private Path DrawPath;
    private Paint DrawPaint;
    private Paint CanvasPaint;
    private Canvas DrawCanvas;
    private Bitmap CanvasBitmap;

    private int w, h;
    private Bitmap _image;

    private void Start()
    {
        CurrentLineColor = Color.Black;
        PenWidth = 5.0f;

        DrawPath = new Path();
        DrawPaint = new Paint
        {
            Color = CurrentLineColor,
            AntiAlias = true,
            StrokeWidth = PenWidth
        };

        DrawPaint.SetStyle(Paint.Style.Stroke);
        DrawPaint.StrokeJoin = Paint.Join.Round;
        DrawPaint.StrokeCap = Paint.Cap.Round;

        CanvasPaint = new Paint
        {
            Dither = true
        };
    }

    public void Clear()
    {
        try
        {
            DrawPath = new Path();
            CanvasBitmap = Bitmap.CreateBitmap(w, h, Bitmap.Config.Argb8888);
            DrawCanvas = new Canvas(CanvasBitmap);

            DrawCanvas.DrawColor(Color.White, PorterDuff.Mode.Multiply);
            CanvasBitmap.EraseColor(Color.Transparent);
            DrawPaint = new Paint
            {
                Color = CurrentLineColor,
                AntiAlias = true,
                StrokeWidth = PenWidth
            };

            DrawPaint.SetStyle(Paint.Style.Stroke);
            DrawPaint.StrokeJoin = Paint.Join.Round;
            DrawPaint.StrokeCap = Paint.Cap.Round;
        }
        catch (Exception e)
        {
            Console.WriteLine(e.Message);
        }

        Invalidate();
    }

    protected override void OnSizeChanged(int w, int h, int oldw, int oldh)
    {
        base.OnSizeChanged(w, h, oldw, oldh);
        if (w > 0 && h > 0)
        {
            try
            {
                CanvasBitmap = Bitmap.CreateBitmap(w, h, Bitmap.Config.Argb8888);
                DrawCanvas = new Canvas(CanvasBitmap);
                this.w = w;
                this.h = h;
            }
            catch (Exception ex)
            {
                Console.WriteLine(ex.Message);
            }
        }
    }

    protected override void OnDraw(Canvas canvas)
    {
        base.OnDraw(canvas);

        DrawPaint.Color = CurrentLineColor;
        DrawPaint.StrokeWidth = PenWidth;
        canvas.DrawBitmap(CanvasBitmap, 0, 0, CanvasPaint);
        canvas.DrawPath(DrawPath, DrawPaint);
    }

    public override bool OnTouchEvent(MotionEvent e)
    {
        var touchX = e.GetX();
        var touchY = e.GetY();

        switch (e.Action)
        {
            case MotionEventActions.Down:
                DrawPath.MoveTo(touchX, touchY);
                break;
            case MotionEventActions.Move:
                DrawPath.LineTo(touchX, touchY);
                break;
            case MotionEventActions.Up:
                DrawCanvas.DrawPath(DrawPath, DrawPaint);
                DrawPath.Reset();
                break;
            default:
                return false;
        }

        Invalidate();

        return true;
    }

    public void LoadImageFromFile()
    {
        if (ImageFilePath != null && ImageFilePath != "")
        {
            _image = BitmapFactory.DecodeFile(ImageFilePath);
        }
    }

    public Bitmap GetImageFromView()
    {
        Bitmap tempBitmap = null;
        try
        {
            tempBitmap = Bitmap.CreateBitmap(w, h, Bitmap.Config.Argb8888);
            DrawCanvas = new Canvas(tempBitmap);

            if (_image != null)
            {
                DrawPaint.SetStyle(Paint.Style.Fill);
                DrawPaint.Color = Color.White;
                DrawCanvas.DrawRect(new Rect(0, 0, w, h), DrawPaint);

                float scaleX = (float)_image.Width / w;
                float scaleY = (float)_image.Height / h;
                Rect outRect = new Rect();

                int outWidth, outHeight;
                if (scaleX > scaleY)
                {
                    outWidth = w;
                    outHeight = (int)(_image.Height / scaleX);
                }
                else
                {
                    outWidth = (int)(_image.Width / scaleY);
                    outHeight = h;
                }

                outRect.Left = w / 2 - outWidth / 2;
                outRect.Top = h / 2 - outHeight / 2;
                outRect.Right = w / 2 + outWidth / 2;
                outRect.Bottom = h / 2 + outHeight / 2;

                DrawCanvas.DrawBitmap(_image, new Rect(0, 0, _image.Width, _image.Height), outRect, DrawPaint);
            }
            else
            {
                DrawPaint.SetStyle(Paint.Style.Fill);
                DrawPaint.Color = Color.White;
                DrawCanvas.DrawRect(new Rect(0, 0, w, h), DrawPaint);
            }

            DrawPaint.Color = CurrentLineColor;
            DrawCanvas.DrawBitmap(CanvasBitmap, 0, 0, CanvasPaint);
            DrawCanvas.DrawPath(DrawPath, DrawPaint);

        }
        catch (Exception ex)
        {
            Console.WriteLine(ex.Message);
        }

        return tempBitmap;
     }
   }
  }

ImageHelper.cs

 using Android.Views;
 using Android.Graphics;
 using Android.Content;
 using System;

 namespace SignaturePadDemo.Droid
 {
  public class DrawView : View
   {
    public DrawView(Context context)
        : base(context)
    {
        Start();
    }

    public Color CurrentLineColor { get; set; }
    public String ImageFilePath { get; set; }

    public float PenWidth { get; set; }

    private Path DrawPath;
    private Paint DrawPaint;
    private Paint CanvasPaint;
    private Canvas DrawCanvas;
    private Bitmap CanvasBitmap;

    private int w, h;
    private Bitmap _image;

    private void Start()
    {
        CurrentLineColor = Color.Black;
        PenWidth = 5.0f;

        DrawPath = new Path();
        DrawPaint = new Paint
        {
            Color = CurrentLineColor,
            AntiAlias = true,
            StrokeWidth = PenWidth
        };

        DrawPaint.SetStyle(Paint.Style.Stroke);
        DrawPaint.StrokeJoin = Paint.Join.Round;
        DrawPaint.StrokeCap = Paint.Cap.Round;

        CanvasPaint = new Paint
        {
            Dither = true
        };
    }

    public void Clear()
    {
        try
        {
            DrawPath = new Path();
            CanvasBitmap = Bitmap.CreateBitmap(w, h, Bitmap.Config.Argb8888);
            DrawCanvas = new Canvas(CanvasBitmap);

            DrawCanvas.DrawColor(Color.White, PorterDuff.Mode.Multiply);
            CanvasBitmap.EraseColor(Color.Transparent);
            DrawPaint = new Paint
            {
                Color = CurrentLineColor,
                AntiAlias = true,
                StrokeWidth = PenWidth
            };

            DrawPaint.SetStyle(Paint.Style.Stroke);
            DrawPaint.StrokeJoin = Paint.Join.Round;
            DrawPaint.StrokeCap = Paint.Cap.Round;
        }
        catch (Exception e)
        {
            Console.WriteLine(e.Message);
        }

        Invalidate();
    }

    protected override void OnSizeChanged(int w, int h, int oldw, int oldh)
    {
        base.OnSizeChanged(w, h, oldw, oldh);
        if (w > 0 && h > 0)
        {
            try
            {
                CanvasBitmap = Bitmap.CreateBitmap(w, h, Bitmap.Config.Argb8888);
                DrawCanvas = new Canvas(CanvasBitmap);
                this.w = w;
                this.h = h;
            }
            catch (Exception ex)
            {
                Console.WriteLine(ex.Message);
            }
        }
    }

    protected override void OnDraw(Canvas canvas)
    {
        base.OnDraw(canvas);

        DrawPaint.Color = CurrentLineColor;
        DrawPaint.StrokeWidth = PenWidth;
        canvas.DrawBitmap(CanvasBitmap, 0, 0, CanvasPaint);
        canvas.DrawPath(DrawPath, DrawPaint);
    }

    public override bool OnTouchEvent(MotionEvent e)
    {
        var touchX = e.GetX();
        var touchY = e.GetY();

        switch (e.Action)
        {
            case MotionEventActions.Down:
                DrawPath.MoveTo(touchX, touchY);
                break;
            case MotionEventActions.Move:
                DrawPath.LineTo(touchX, touchY);
                break;
            case MotionEventActions.Up:
                DrawCanvas.DrawPath(DrawPath, DrawPaint);
                DrawPath.Reset();
                break;
            default:
                return false;
        }

        Invalidate();

        return true;
    }

    public void LoadImageFromFile()
    {
        if (ImageFilePath != null && ImageFilePath != "")
        {
            _image = BitmapFactory.DecodeFile(ImageFilePath);
        }
    }

    public Bitmap GetImageFromView()
    {
        Bitmap tempBitmap = null;
        try
        {
            tempBitmap = Bitmap.CreateBitmap(w, h, Bitmap.Config.Argb8888);
            DrawCanvas = new Canvas(tempBitmap);

            if (_image != null)
            {
                DrawPaint.SetStyle(Paint.Style.Fill);
                DrawPaint.Color = Color.White;
                DrawCanvas.DrawRect(new Rect(0, 0, w, h), DrawPaint);

                float scaleX = (float)_image.Width / w;
                float scaleY = (float)_image.Height / h;
                Rect outRect = new Rect();

                int outWidth, outHeight;
                if (scaleX > scaleY)
                {
                    outWidth = w;
                    outHeight = (int)(_image.Height / scaleX);
                }
                else
                {
                    outWidth = (int)(_image.Width / scaleY);
                    outHeight = h;
                }

                outRect.Left = w / 2 - outWidth / 2;
                outRect.Top = h / 2 - outHeight / 2;
                outRect.Right = w / 2 + outWidth / 2;
                outRect.Bottom = h / 2 + outHeight / 2;

                DrawCanvas.DrawBitmap(_image, new Rect(0, 0, _image.Width, _image.Height), outRect, DrawPaint);
            }
            else
            {
                DrawPaint.SetStyle(Paint.Style.Fill);
                DrawPaint.Color = Color.White;
                DrawCanvas.DrawRect(new Rect(0, 0, w, h), DrawPaint);
            }

            DrawPaint.Color = CurrentLineColor;
            DrawCanvas.DrawBitmap(CanvasBitmap, 0, 0, CanvasPaint);
            DrawCanvas.DrawPath(DrawPath, DrawPaint);

        }
        catch (Exception ex)
        {
            Console.WriteLine(ex.Message);
        }

        return tempBitmap;
     }
  }
 }

Xamarin.iOS:

ISignService.cs

using System;
using SignaturePadDemo.iOS;
using Xamarin.Forms;

[assembly: Dependency(typeof(ISignService))]
namespace SignaturePadDemo.iOS
{
 public class ISignService : ISign
 {
    public string Sign()
    {
        string savedFileName = Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments) + "/temp_" + DateTime.Now.ToString("yyyy_mm_dd_hh_mm_ss") + ".jpg";
        return savedFileName;
     }
    }
 }

DrawView.cs

using System;
using UIKit;
using System.Drawing;
using CoreGraphics;
using System.Collections.Generic;
using Foundation;

namespace SignaturePadDemo.iOS
{
  public class DrawView : UIView
   {
    public DrawView(RectangleF frame) : base(frame)
    {
        DrawPath = new CGPath();
        CurrentLineColor = UIColor.Black;
        PenWidth = 3.0f;
        Lines = new List<VESLine>();
    }

    private PointF PreviousPoint;
    private CGPath DrawPath;
    private byte IndexCount;
    private UIBezierPath CurrentPath;
    private List<VESLine> Lines;

    public UIColor CurrentLineColor { get; set; }
    public String ImageFilePath { get; set; }
    public float PenWidth { get; set; }

    private UIImage _image = null;

    public void Clear()
    {
        Lines.Clear();
        DrawPath.Dispose();
        DrawPath = new CGPath();
        SetNeedsDisplay();
    }

    public override void TouchesBegan(NSSet touches, UIEvent evt)
    {
        IndexCount++;

        var path = new UIBezierPath
        {
            LineWidth = PenWidth
        };

        var touch = (UITouch)touches.AnyObject;
        PreviousPoint = (PointF)touch.PreviousLocationInView(this);

        var newPoint = touch.LocationInView(this);
        path.MoveTo(newPoint);

        InvokeOnMainThread(SetNeedsDisplay);

        CurrentPath = path;

        var line = new VESLine
        {
            Path = CurrentPath,
            Color = CurrentLineColor,
            Index = IndexCount
        };

        Lines.Add(line);
    }

    public override void TouchesMoved(NSSet touches, UIEvent evt)
    {
        var touch = (UITouch)touches.AnyObject;
        var currentPoint = touch.LocationInView(this);

        if (Math.Abs(currentPoint.X - PreviousPoint.X) >= 4 ||
            Math.Abs(currentPoint.Y - PreviousPoint.Y) >= 4)
        {

            var newPoint = new PointF((float)(currentPoint.X + PreviousPoint.X) / 2, (float)(currentPoint.Y + PreviousPoint.Y) / 2);

            CurrentPath.AddQuadCurveToPoint(newPoint, PreviousPoint);
            PreviousPoint = (PointF)currentPoint;
        }
        else
        {
            CurrentPath.AddLineTo(currentPoint);
        }

        InvokeOnMainThread(SetNeedsDisplay);
    }

    public override void TouchesEnded(NSSet touches, UIEvent evt)
    {
        InvokeOnMainThread(SetNeedsDisplay);
    }

    public override void TouchesCancelled(NSSet touches, UIEvent evt)
    {
        InvokeOnMainThread(SetNeedsDisplay);
    }

    public override void Draw(CGRect rect)
    {
        foreach (VESLine p in Lines)
        {
            p.Color.SetStroke();
            p.Path.Stroke();
        }
    }

    public void LoadImageFromFile()
    {
        if (ImageFilePath != null && ImageFilePath != "")
        {
            _image = ImageHelper.GetRotateImage(ImageFilePath);
        }
    }

    public UIImage GetImageFromView()
    {
        RectangleF rect;
        rect = (RectangleF)Frame;

        UIGraphics.BeginImageContext(rect.Size);

        CGContext context = UIGraphics.GetCurrentContext();
        if (_image != null)
            context.DrawImage(Frame, _image.CGImage);
        this.Layer.RenderInContext(context);

        UIImage image = UIGraphics.GetImageFromCurrentImageContext();

        UIGraphics.EndImageContext();

        return image;
      }
   }
 }

ImageHelper.cs

 using System;
 using System.Drawing;
 using CoreGraphics;
 using Foundation;
 using UIKit;

 namespace SignaturePadDemo.iOS
 {
    public class ImageHelper
  {
    public static UIImage GetRotateImage(String imagePath)
    {
        UIImage image = UIImage.FromFile(imagePath);
        CGImage imgRef = image.CGImage;

        float width = imgRef.Width;
        float height = imgRef.Height;

        CGAffineTransform transform = CGAffineTransform.MakeIdentity();
        RectangleF bounds = new RectangleF(0, 0, width, height);
        SizeF imageSize = new SizeF(width, height);
        float boundHeight;
        UIImageOrientation orient = image.Orientation;
        switch (orient)
        {

            case UIImageOrientation.Up:
                transform = CGAffineTransform.MakeIdentity();
                break;

            case UIImageOrientation.UpMirrored:
                transform = CGAffineTransform.MakeTranslation(imageSize.Width, 0.0f);
                transform.Scale(-1.0f, 1.0f);
                break;

            case UIImageOrientation.Down:
                transform.Rotate((float)Math.PI);
                transform.Translate(imageSize.Width, imageSize.Height);
                break;

            case UIImageOrientation.DownMirrored:
                transform = CGAffineTransform.MakeTranslation(0.0f, imageSize.Height);
                transform.Scale(1.0f, -1.0f);
                break;

            case UIImageOrientation.LeftMirrored:
                boundHeight = bounds.Size.Height;
                bounds.Height = bounds.Size.Width;
                bounds.Width = boundHeight;
                transform.Scale(-1.0f, 1.0f);
                transform.Rotate((float)Math.PI / 2.0f);
                break;

            case UIImageOrientation.Left:
                boundHeight = bounds.Size.Height;
                bounds.Height = bounds.Size.Width;
                bounds.Width = boundHeight;
                transform = CGAffineTransform.MakeRotation((float)Math.PI / 2.0f);
                transform.Translate(imageSize.Height, 0.0f);
                break;

            case UIImageOrientation.RightMirrored:
                boundHeight = bounds.Size.Height;
                bounds.Height = bounds.Size.Width;
                bounds.Width = boundHeight;
                transform = CGAffineTransform.MakeTranslation(imageSize.Height, imageSize.Width);
                transform.Scale(-1.0f, 1.0f);
                transform.Rotate(3.0f * (float)Math.PI / 2.0f);
                break;

            case UIImageOrientation.Right:
                boundHeight = bounds.Size.Height;
                bounds.Height = bounds.Size.Width;
                bounds.Width = boundHeight;
                transform = CGAffineTransform.MakeRotation(-(float)Math.PI / 2.0f);
                transform.Translate(0.0f, imageSize.Width);
                break;

            default:
                break;

        }

        UIGraphics.BeginImageContext(bounds.Size);

        CGContext context = UIGraphics.GetCurrentContext();

        context.ConcatCTM(transform);

        context = UIGraphics.GetCurrentContext();
        context.DrawImage(new RectangleF(0, 0, width, height), imgRef);
        UIImage imageCopy = UIGraphics.GetImageFromCurrentImageContext();
        UIGraphics.EndImageContext();

        return imageCopy;
    }

    public static bool SaveRotateImage(String imagePath)
    {
        UIImage imageCopy = GetRotateImage(imagePath);

        NSData data = imageCopy.AsJPEG();
        NSError error = new NSError();
        bool bSuccess = data.Save(imagePath, true, out error);

        return bSuccess;
      }
   }
}

VESLine.cs

 using System;
 using UIKit;

 namespace SignaturePadDemo.iOS
  {
   public class VESLine
   {
    public UIBezierPath Path
    {
        get;
        set;
    }

    public UIColor Color
    {
        get;
        set;
    }

    public byte Index
    {
        get;
        set;
     }
   }
 }

你可以从here下载

enter image description here


0
投票

正如@Jason评论的那样,使用SignaturePad。

NuGet可以在这里找到:https://www.nuget.org/packages/Xamarin.Controls.SignaturePad.Forms

它基本上适用于任何平台。

资料来源:https://github.com/xamarin/SignaturePad

示例页面可能是这样的:

<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             xmlns:signature="clr-namespace:SignaturePad.Forms;assembly=SignaturePad.Forms"
             x:Class="Samples.Views.SignatureXamlView">

    <Grid>
        <signature:SignaturePadView />
    </Grid>

</ContentPage>
© www.soinside.com 2019 - 2024. All rights reserved.