Mike's Dev Blog

Drawing with CoreGraphics in MonoTouch

Posted in monotouch by mikebluestein on February 21, 2010

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());
				}
			}  
		}

About these ads

13 Responses

Subscribe to comments with RSS.

  1. MonoTouch.Info said, on February 21, 2010 at 11:16 pm

    MonoTouch Article – Drawing with CoreGraphics in MonoTouch…

    Thank you for submitting this entry – Trackback from MonoTouch.Info…

  2. Jeremy Schwartz said, on July 14, 2010 at 9:25 pm

    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

    • mikebluestein said, on July 15, 2010 at 11:59 pm

      take a look at the sample project I created here: http://github.com/mikebluestein/iBabySmash

      • Sonia said, on August 31, 2012 at 7:09 pm

        hmm I am still unclear on how to procede exactly to wired up the DrawingView class in Interface Builder to be under DrawingViewController. I am sorry if I seem lazy but I have a hard time following your book since I am a newbie and have a hard time transposing your tutorials with the new version of xcode.

        Best Regards,

        Thank you,

        Sonia

  3. Chandran said, on July 21, 2011 at 5:41 am

    Thank’s for the tutorial sir,

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

    • mikebluestein said, on July 21, 2011 at 9:09 pm

      I think I’d use OpenGL for this use case. There’s a paint sample here that should get you started: https://github.com/migueldeicaza/monotouch-samples/tree/master/GLPaint-GV

      • Chandran said, on July 26, 2011 at 11:11 am

        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.

      • Chandran said, on August 5, 2011 at 5:49 am

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

  4. Chandran said, on July 21, 2011 at 7:08 am

    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);

    • tkurkcuoglu said, on August 24, 2011 at 12:45 am

      you should try the given code. at Line 13 in the first segment of code, path is declared to be global in the class. at line 32, it is recreated everytime the Draw method gets hit. that causes the large gap you are talking about. if you comment out the line 32, you get the thing you want. in short, the lines added to the path has to be accumulated, i guess.

      • Chandran said, on October 3, 2011 at 9:43 am

        Thank you for the reply,
        I have cleared the signature concept and it is fine.
        now i am including camera concept using Avfoundation, how can i save the image?
        any idea or suggestion would be appreciated.

      • mikebluestein said, on October 3, 2011 at 12:36 pm

        There’s a wiki post about storing files here: http://wiki.ios.xamarin.com/HowTo/Files/HowTo%3a_Store_Files

  5. Chandran said, on October 6, 2011 at 5:09 am

    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 )

Google+ photo

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

Connecting to %s

Follow

Get every new post delivered to your Inbox.