I had the same problem described in the question. I looked at @Dmitry's answer above, but was completely different from what I have, and that would require a lot of changes. so I followed @Stephane's advice above and just executed the MoveTouches queue, which worked just fine. Thank you, guys.
I put my decision here if someone needs it. Please note that I capture the signature, not the signature as an image. We have another algorithm for rendering these points using different settings.
using MonoTouch.CoreGraphics; using MonoTouch.UIKit; using System.Drawing; using System; using Leopard.Interfaces; using MonoTouch.Foundation; using Leopard.Mobile.Core.Signature; using Leopard.Mobile.Core.Drawing; using Leopard.Interfaces.Drawing; using Leopard.Interfaces.Screens.Controls; using System.Linq; using System.Collections.Concurrent; namespace Leopard.Mobile.Controls { public class SignatureView : LeopardControlBase, ISignatureView { public SignatureView (RectangleF frame) : base(frame) { base.Frame = frame; ViewFrame = new LeopardFrame { X = (int)frame.X, Y = (int) frame.Y, Width = frame.Width, Height = frame.Height }; _DrawPath = new CGPath(); SetupAppearance(); _ScalingFactor = new LeopardFrame { Width = 1, Height = 1 }; DrawWatermarks(); } public void Initialise(int penWidth, WatermarkSettings watermarks, string backgroundImageFileName) { PenWidth = penWidth; Watermarks = watermarks; BackgroundImageFileName = backgroundImageFileName; var dimensions = new LeopardFrame { Width = Frame.Width, Height = Frame.Height }; _SignatureData = new SignatureData(dimensions, _ScalingFactor, watermarks); } public void Clear () { _DrawPath.Dispose(); _DrawPath = new CGPath(); _FingerDraw = false; _TouchLocation = new PointF(0, 0); _PrevTouchLocation = new PointF(0, 0); SetNeedsDisplay(); _SignatureData.Clear(); DrawWatermarks(); _TouchsQueue = new ConcurrentQueue<TouchsQueue>(); } public override void TouchesBegan(NSSet touches, UIEvent evt) { base.TouchesBegan (touches, evt); UITouch touch = touches.AnyObject as UITouch; this._FingerDraw = true; this._TouchLocation = touch.LocationInView (this); this._PrevTouchLocation = touch.PreviousLocationInView (this); this.SetNeedsDisplay (); _SignatureData.AddPoint(SignatureState.Start, (int)this._TouchLocation.X, (int)this._TouchLocation.Y); } public override void TouchesEnded(NSSet touches, UIEvent e) { base.TouchesEnded(touches, e); if (this._FingerDraw) { UITouch touch = touches.AnyObject as UITouch; _TouchLocation = touch.LocationInView(this); _PrevTouchLocation = touch.PreviousLocationInView(this); _FingerDraw = false; _SignatureData.AddPoint(SignatureState.End, (int)this._TouchLocation.X, (int)this._TouchLocation.Y); } } public override void TouchesMoved (NSSet touches, UIEvent evt) { base.TouchesMoved (touches, evt); UITouch touch = touches.AnyObject as UITouch; _TouchLocation = touch.LocationInView(this); _PrevTouchLocation = touch.PreviousLocationInView(this); _TouchsQueue.Enqueue(new TouchsQueue {TouchLocation = _TouchLocation, PrevTouchLocation = _PrevTouchLocation }); _SignatureData.AddPoint(SignatureState.Move, (int)this._TouchLocation.X, (int)this._TouchLocation.Y); SetNeedsDisplay(); } public override void Draw (RectangleF rect) { base.Draw (rect); if (_DrawPath != null) { using (CGContext context = UIGraphics.GetCurrentContext()) { if (context != null) { DrawSignatureLines(context); } } } } private void DrawSignatureLines(CGContext context) { TouchsQueue queueElement = null; while(_TouchsQueue.TryDequeue(out queueElement)) { if (queueElement != null) { context.SetStrokeColor(UIColor.Black.CGColor); context.SetLineWidth(PenWidth); context.SetLineJoin(CGLineJoin.Round); context.SetLineCap(CGLineCap.Round); _DrawPath.MoveToPoint(queueElement.PrevTouchLocation); _DrawPath.AddLineToPoint(queueElement.TouchLocation); context.AddPath(_DrawPath); context.DrawPath(CGPathDrawingMode.Stroke); } } } public void Add(IControl control) { var view = control as UIView; if (view != null) { EnsureAddingWatermarkControl(view); } } public string GetSignatureData() { var result = string.Empty; if (_SignatureData != null) { try { result = _SignatureData.ExtractAsString(); } catch (Exception exception) { OnFailedWithException(exception); } } return result; } #region Implementation private PointF _TouchLocation; private PointF _PrevTouchLocation; private CGPath _DrawPath; private bool _FingerDraw; private ConcurrentQueue<TouchsQueue> _TouchsQueue = new ConcurrentQueue<TouchsQueue>(); private ILeopardFrame _ScalingFactor; private SignatureData _SignatureData { get; set; } public SignatureData SignatureData { get { return _SignatureData; } } public event SignatureFailedWithExceptionHandler SignatureFailedWithException; public string BackgroundImageFileName {get;set;} public int PenWidth { get; set; } public WatermarkSettings Watermarks {get;set;} public ILeopardFrame ViewFrame { get; set; } private void OnFailedWithException(Exception exception) { if (SignatureFailedWithException != null) { SignatureFailedWithException(exception); } } private void EnsureAddingWatermarkControl(UIView view) { var existingView = this.Subviews.ToList().FirstOrDefault( v => v is IControl && v.Frame.X == view.Frame.X && v.Frame.Y == view.Frame.Y); if (existingView != null) { existingView.RemoveFromSuperview(); existingView.Dispose(); } this.AddSubview(view); } private void DrawWatermarks() { if (Watermarks != null) { Watermarks.DrawWatermarks(this, _ScalingFactor); } } private void SetupAppearance () { BackgroundColor = UIColor.White; Layer.BorderWidth = 5f; Layer.BorderColor = UIColor.FromRGB ( Constants.LeopardBackgroundColors.Red, Constants.LeopardBackgroundColors.Green, Constants.LeopardBackgroundColors.Blue ).CGColor; } #endregion } public class TouchsQueue { public PointF TouchLocation {get;set;} public PointF PrevTouchLocation { get; set; } }
}
source share