Drawing with CoreGraphics in MonoTouch

CoreGraphics allows you to do custom drawing on the iPhone. MonoTouch exposes this in the namespace MonoTouch.CoreGraphics. This allows you to do all sorts of custom drawing. Here I’ll present an introductory example that shows how to draw a triangle in a custom view along with determining if the triangle was touched. Even as drawing complexity increases, you’ll find the code to be quite similar in general, just that there will be more of it.

For the example I created a new MonoTouch window-based app and added a new ViewController from the ViewController with View template, naming it DrawingViewController.xib. I then added a class called DrawingView, subclassed from UIView, that I wired up in Interface Builder to be the view under DrawingViewController. After that I decorated the DrawingView class with the Resigister attribute so it will be available for the Objective-C runtime. As it’s being created from the xib, I also included the constructor that takes an IntPtr. See some of the tutorials on the monotouch wiki or the articles aggregated at monotouch.info if you need to review the details of how to wire things up.

With the DrawingView class in place, you can override the Draw (RectangleF rect) method to implement custom drawing. You implement what you want to draw in the Draw method and CocoaTouch will call it at runtime during event loop processing. To draw you need to:

  1. Get a graphics context
  2. Set up drawing attributes
  3. Create some geometry from drawing primitives
  4. Call a Draw or Stroke method

Here’s a simple example that draws a rectangle and fills it with a color:

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

namespace CoreGraphicsDemo
{


	[Register("DrawingView")]
	public class DrawingView : UIView
	{
		CGPath path;
		
		public DrawingView (IntPtr p) : base(p)
		{
		}
			
		public override void Draw (RectangleF rect)
		{
			base.Draw (rect);
			
			//get graphics context
			CGContext gctx = UIGraphics.GetCurrentContext ();
			
			//set up drawing attributes
			gctx.SetLineWidth(4);
			UIColor.Purple.SetFill ();
			UIColor.Black.SetStroke ();
		
			//create geometry
		    path = new CGPath ();
			
			path.AddLines(new PointF[]{
				new PointF(100,200),
				new PointF(160,100), 
				new PointF(220,200)});
			
			path.CloseSubpath();
			
			//add geometry to graphics context and draw it
			gctx.AddPath(path);		
			gctx.DrawPath(CGPathDrawingMode.FillStroke);	
		}
        ...

To respond to touches on the triangle you can override TouchesBegan and make use of the LocationInView method on UITouch like this:

		public override void TouchesBegan (NSSet touches, UIEvent evt)
		{
			base.TouchesBegan (touches, evt);
			
			UITouch touch = touches.AnyObject as UITouch;
			
		    if(touch != null)
			{
				PointF pt = touch.LocationInView(this);
				
				if(path.ContainsPoint(pt, true))
				{
					Console.WriteLine("Hit {0}", pt.ToString());
				}
				else
				{
					Console.WriteLine("No Hit {0}", pt.ToString());
				}
			}  
		}

13 thoughts on “Drawing with CoreGraphics in MonoTouch

  1. Pingback: MonoTouch.Info
  2. Hi —

    First, thanks for posting this tutorial. I am new to MonoTouch development and have done some of the basic tutorials, but I am unclear exactly how to wire up the DrawingView class so it is the view under DrawingViewController. I can’t seem to see a reference to DrawingView in IB at all. DrawingView should be in its own class file, right?

    Any help you could provide would be greatly appreciated.

    Thanks.

    Jeremy Schwartz

  3. Thank’s for the tutorial sir,

    I am trying signature concept in monotouch can you help me with this,Any suggestions or any idea.

      • Thanks for the tutorial,

        But when i run the code in monodevelop i get the following error.

        Error connecting stdout and stderr (127.0.0.1:10001)
        Detected an attempt to call a symbol in system libraries that is not present on the iPhone:
        open$UNIX2003 called from function _ZN4llvm12MemoryBuffer7getFileEPKcPSsx in image libLLVMContainer.dylib.
        Detected an attempt to call a symbol in system libraries that is not present on the iPhone:
        fstat$INODE64 called from function _ZN4llvm12MemoryBuffer7getFileEPKcPSsx in image libLLVMContainer.dylib.
        Detected an attempt to call a symbol in system libraries that is not present on the iPhone:
        mmap$UNIX2003 called from function _ZN4llvm3sys4Path14MapInFilePagesEiy in image libLLVMContainer.dylib.
        Detected an attempt to call a symbol in system libraries that is not present on the iPhone:
        close$UNIX2003 called from function _ZN4llvm12MemoryBuffer7getFileEPKcPSsx in image libLLVMContainer.dylib.

        Does this caused any native library in monodevelop?
        Please help.

      • Thanks,
        That is a wonderful tutorial.
        Can you provide me how to save that as image or any idea would be appreciated.
        Please…

  4. Hai,

    Thank’s for the tutorial,

    I am new to monotouch.
    I have created a signature concept using mouse touches began event.
    When i move the cursor slowly the coordinates are perfectly highligting,but when the cursor movement is fast there is a large gap between Consequent coordinates.Please help..

    The code
    var currentPoint = new PointF();
    var lastPoint = new PointF();
    UITouch touch = touches.AnyObject as UITouch;
    currentPoint = touch.LocationInView(this);
    currentPoint.Y -=7;
    currentPoint.Y -= 1;
    currentPoint.X -=1;
    UIGraphics.BeginImageContext(this.Frame.Size);
    CGContext cont = UIGraphics.GetCurrentContext();
    if (this.Image != null)
    {
    cont.TranslateCTM(0f, this.Frame.Size.Height);
    cont.ScaleCTM(1.0f, -1.0f);
    cont.DrawImage(new RectangleF(0, 0, this.Frame.Size.Width, this.Frame.Size.Height), this.Image.CGImage);
    cont.ScaleCTM(1.0f, -1.0f);
    cont.TranslateCTM(0f, -this.Frame.Size.Height);
    }
    cont.SetLineCap(CGLineCap.Round);
    cont.SetLineWidth(3f);
    cont.SetRGBStrokeColor(0f,0f,0f,1.00f);
    cont.BeginPath();
    cont.MoveTo(currentPoint.X, currentPoint.Y);
    cont.AddLineToPoint(currentPoint.X,currentPoint.Y);
    cont.AddLineToPoint(currentPoint.X,currentPoint.Y);
    Console.WriteLine(“CurrentPoint: ” + currentPoint.X + “:” + currentPoint.Y.ToString());
    Console.WriteLine(“LastPoint: ” + lastPoint.X + “:” + lastPoint.Y.ToString());
    cont.DrawPath(CGPathDrawingMode.Stroke);
    this.Image = UIGraphics.GetImageFromCurrentImageContext();
    UIGraphics.EndImageContext();
    lastPoint = currentPoint;
    NSError err = new NSError();
    string img_path=”path”;
    this.Image.AsJPEG().Save(img_path,true, out err);

  5. Thank you,
    Now i can save image in the device path.
    I am capturing image using AVFoundation Camera concept.
    My camera is in landscape mode.
    How can i change it to potrait mode.
    any help would be appreciated.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s