How to draw a NSImage like images in NSButtons (with a deepness)? - objective-c

Is there any way to draw an NSImage like images in NSButtons or other cocoa interface elements?
Here are examples:
Apple uses pdf's with black icons:

If you simply want this effect to be applied when you use your own images in a button, use [myImage setTemplate:YES]. There is no built-in way to draw images with this effect outside of a button that has the style shown in your screenshots.
You can however replicate the effect using Core Graphics. If you look closely, the effect consists of a horizontal gradient, a white drop shadow and a dark inner shadow (the latter is the most difficult).
You could implement this as a category on NSImage:
//NSImage+EtchedDrawing.h:
#interface NSImage (EtchedImageDrawing)
- (void)drawEtchedInRect:(NSRect)rect;
#end
//NSImage+EtchedDrawing.m:
#implementation NSImage (EtchedImageDrawing)
- (void)drawEtchedInRect:(NSRect)rect
{
NSSize size = rect.size;
CGFloat dropShadowOffsetY = size.width <= 64.0 ? -1.0 : -2.0;
CGFloat innerShadowBlurRadius = size.width <= 32.0 ? 1.0 : 4.0;
CGContextRef c = [[NSGraphicsContext currentContext] graphicsPort];
//save the current graphics state
CGContextSaveGState(c);
//Create mask image:
NSRect maskRect = rect;
CGImageRef maskImage = [self CGImageForProposedRect:&maskRect context:[NSGraphicsContext currentContext] hints:nil];
//Draw image and white drop shadow:
CGContextSetShadowWithColor(c, CGSizeMake(0, dropShadowOffsetY), 0, CGColorGetConstantColor(kCGColorWhite));
[self drawInRect:maskRect fromRect:NSMakeRect(0, 0, self.size.width, self.size.height) operation:NSCompositeSourceOver fraction:1.0];
//Clip drawing to mask:
CGContextClipToMask(c, NSRectToCGRect(maskRect), maskImage);
//Draw gradient:
NSGradient *gradient = [[[NSGradient alloc] initWithStartingColor:[NSColor colorWithDeviceWhite:0.5 alpha:1.0]
endingColor:[NSColor colorWithDeviceWhite:0.25 alpha:1.0]] autorelease];
[gradient drawInRect:maskRect angle:90.0];
CGContextSetShadowWithColor(c, CGSizeMake(0, -1), innerShadowBlurRadius, CGColorGetConstantColor(kCGColorBlack));
//Draw inner shadow with inverted mask:
CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB();
CGContextRef maskContext = CGBitmapContextCreate(NULL, CGImageGetWidth(maskImage), CGImageGetHeight(maskImage), 8, CGImageGetWidth(maskImage) * 4, colorSpace, kCGImageAlphaPremultipliedLast);
CGColorSpaceRelease(colorSpace);
CGContextSetBlendMode(maskContext, kCGBlendModeXOR);
CGContextDrawImage(maskContext, maskRect, maskImage);
CGContextSetRGBFillColor(maskContext, 1.0, 1.0, 1.0, 1.0);
CGContextFillRect(maskContext, maskRect);
CGImageRef invertedMaskImage = CGBitmapContextCreateImage(maskContext);
CGContextDrawImage(c, maskRect, invertedMaskImage);
CGImageRelease(invertedMaskImage);
CGContextRelease(maskContext);
//restore the graphics state
CGContextRestoreGState(c);
}
#end
Example usage in a view:
- (void)drawRect:(NSRect)dirtyRect
{
[[NSColor colorWithDeviceWhite:0.8 alpha:1.0] set];
NSRectFill(self.bounds);
NSImage *image = [NSImage imageNamed:#"MyIcon.pdf"];
[image drawEtchedInRect:self.bounds];
}
This would give you the following result (shown in different sizes):
You may need to experiment a bit with the gradient colors and offset/blur radius of the two shadows to get closer to the original effect.

If you don't mind calling a private API, you can let the operating system (CoreUI) do the shading for you. You need a few declarations:
typedef CFTypeRef CUIRendererRef;
extern void CUIDraw(CUIRendererRef renderer, CGRect frame, CGContextRef context, CFDictionaryRef object, CFDictionaryRef *result);
#interface NSWindow(CoreUIRendererPrivate)
+ (CUIRendererRef)coreUIRenderer;
#end
And for the actual drawing:
CGRect drawRect = CGRectMake(x, y, width, height);
CGImageRef cgimage = your_image;
CFDictionaryRef dict = (CFDictionaryRef) [NSDictionary dictionaryWithObjectsAndKeys:
#"backgroundTypeRaised", #"backgroundTypeKey",
[NSNumber numberWithBool:YES], #"imageIsGrayscaleKey",
cgimage, #"imageReferenceKey",
#"normal", #"state",
#"image", #"widget",
[NSNumber numberWithBool:YES], #"is.flipped",
nil];
CUIDraw ([NSWindow coreUIRenderer], drawRect, cg, dict, nil);
CGImageRelease (cgimage);
This will take the alpha channel of cgimage and apply the embossing effect as seen on toolbar buttons. You may or may not need the "is.flipped" line. Remove it if your result is upside-down.
There are a bunch of variations:
kCUIPresentationStateKey = kCUIPresentationStateInactive: The window is not active, the image will be lighter.
state = rollover: Only makes sense with the previous option. This means you are hovering over the image, the window is inactive, but the button is sensitive (click-through is enabled). It will become darker.
state = pressed: Occurs when the button is pressed. The icon gets slightly darker.
Bonus tip: To find out stuff like this, you can use the SIMBL plugin CUITrace. It prints out all the CoreUI invocations of a target app. This is a treasure trove if you have to draw your own native-looking UI.

Here's a much simpler solution: just create a cell and let it draw. No mucking around with private APIs or Core Graphics.
Code could look similar to the following:
NSButtonCell *buttonCell = [[NSButtonCell alloc] initImageCell:image];
buttonCell.bordered = YES;
buttonCell.bezelStyle = NSTexturedRoundedBezelStyle;
// additional configuration
[buttonCell drawInteriorWithFrame: someRect inView:self];
You can use different cells and configurations depending on the look you want to have (eg. NSImageCell with NSBackgroundStyleDark if you want the inverted look in a selected table view row)
And as a bonus, it will automatically look correct on all versions of OS X.

To get to draw correctly within any rect, the CGContextDrawImage and CGContextFillRect for the inner mask must have the origin of (0,0). then when you draw the image for the inner shadow you can then reuse the mask rect. So ends up looking like:
CGRect cgRect = CGRectMake( 0, 0, maskRect.size.width, maskRect.size.height );
CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB();
CGContextRef maskContext = CGBitmapContextCreate( NULL, CGImageGetWidth( maskImage ), CGImageGetHeight( maskImage ), 8, CGImageGetWidth( maskImage ) * 4, colorSpace, kCGImageAlphaPremultipliedLast );
CGColorSpaceRelease( colorSpace );
CGContextSetBlendMode( maskContext , kCGBlendModeXOR );
CGContextDrawImage( maskContext, cgRect, maskImage );
CGContextSetRGBFillColor( maskContext, 1.0, 1.0, 1.0, 1.0 );
CGContextFillRect( maskContext, cgRect );
CGImageRef invertedMaskImage = CGBitmapContextCreateImage( maskContext );
CGContextDrawImage( context, maskRect, invertedMaskImage );
CGImageRelease( invertedMaskImage );
CGContextRelease( maskContext );
CGContextRestoreGState( context );
You also have to leave a 1px border around the outside of the image or the shadows won't work correctly.

Related

ios CCLabelTTF colored subclass with Core Text

Good day to all.
At the moment I am trying to implement CCLabelTTF subclass with suppport of NSAttributedString to get multi-colored label. And I am hampered by lack of CoreText and CoreGraphics knowledge.
After reading few guides I, created CCTexture2D category to create texture using NSAttributedString object.
Here is my drawing code:
data = calloc(POTHigh, POTWide * 2);
colorSpace = CGColorSpaceCreateDeviceGray();
context = CGBitmapContextCreate(data, POTWide, POTHigh, 8, POTWide, colorSpace, kCGImageAlphaNone);
CGColorSpaceRelease(colorSpace);
if( ! context )
{
free(data);
[self release];
return nil;
}
UIGraphicsPushContext(context);
CGContextTranslateCTM(context, 0.0f, POTHigh);
CGContextScaleCTM(context, 1.0f, -1.0f);
// draw attributed string to context
CTFramesetterRef frameSetter = CTFramesetterCreateWithAttributedString((CFAttributedStringRef)string);
CGMutablePathRef path = CGPathCreateMutable();
CGPathAddRect(path, NULL, CGRectMake(0.f, 0.f, dimensions.width, dimensions.height));
CTFrameRef frame = CTFramesetterCreateFrame(frameSetter, CFRangeMake(0, 0), path, NULL);
CTFrameDraw(frame, context);
UIGraphicsPopContext();
CFRelease(frame);
CGPathRelease(path);
CFRelease(frameSetter);
And now I have few troubles:
The first one - my texture is shown flipped vertically. I thought, that these lines
CGContextTranslateCTM(context, 0.0f, POTHigh);
CGContextScaleCTM(context, 1.0f, -1.0f);
should prevent this.
The second one, if I create RGB context, I cannot see anything on the screen. I tried to create RGB context with these lines.
colorSpace = CGColorSpaceCreateDeviceRGB();
context = CGBitmapContextCreate(data, POTWide, POTHigh, 8, POTWide * 4, colorSpace, kCGImageAlphaPremultipliedFirst | kCGBitmapByteOrder32Big);
I tried to google, but don't find anything related to my issues =( Any help(links or suggestions) is appreciated.
Couple things to try:
Your data allocation isn't big enough for RGB. Try: data = calloc(POTHigh, POTWide * 4); for RGB color space.
CTFrameDraw draws in relation to GL coords so you don't need to use CGContextScaleCTM(context, 1.0f, -1.0f);
that line was put in the original CCTexture2D creation for a CCLabelTTF because it used NSString's drawInRect: which draws in relation to UIKit coords.
Maybe try other alpha mask flags...? Check out Apple's documentation on Supported Pixel Formats for iOS to see what your options are.
You may want to take a look at ActiveTextView-iOS (https://github.com/storify/ActiveTextView-iOS). It may be of use.
use this to get color texture:
context = CGBitmapContextCreate(data, POTWide, POTHigh, 8, POTWide, colorSpace, kCGImageAlphaPremultipliedLast);

Xcode Screenshot EAGLContext [duplicate]

This question already has answers here:
Closed 10 years ago.
Possible Duplicate:
How to get UIImage from EAGLView?
So I was just wondering if anybody knows any way to save what is stored in an EAGLContext as a UIImage.
I am currently using:
UIGraphicsBeginImageContext(CGSizeMake(768, 1024));
[self.layer renderInContext:UIGraphicsGetCurrentContext()];
UIImage *viewImage = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
in other apps I have and this works fine, but obviously, EAGLContext doesn't have a .layer property. I've tried casting to UIView, but that - unsurprisingly - doesn't work:
UIView *newView = [[UIView alloc] init];
newView = (UIView *)context;
I am drawing to an EAGLContext property on a UIView (technically an EAGLContext on a UIView on another UIView on a View Controller, but I figure that shouldn't make any difference) using OpenGLES 1.
If anybody knows anything about this, even if its just that I'm completely barking up an impossible tree, please let me know!
Matt
After a few days I finally got a working solution to this. There is code provided by Apple which produces an UIImage from an EAGLView. Then you simply need to flip the image vertically since UIKit is upside down. The link to the documentation where I found this method doesn't exist anymore.
Method to capture EAGLView:
-(UIImage *)drawableToCGImage
{
GLint backingWidth2, backingHeight2;
//Bind the color renderbuffer used to render the OpenGL ES view
// If your application only creates a single color renderbuffer which is already bound at this point,
// this call is redundant, but it is needed if you're dealing with multiple renderbuffers.
// Note, replace "_colorRenderbuffer" with the actual name of the renderbuffer object defined in your class.
glBindRenderbufferOES(GL_RENDERBUFFER_OES, viewRenderbuffer);
// Get the size of the backing CAEAGLLayer
glGetRenderbufferParameterivOES(GL_RENDERBUFFER_OES, GL_RENDERBUFFER_WIDTH_OES, &backingWidth2);
glGetRenderbufferParameterivOES(GL_RENDERBUFFER_OES, GL_RENDERBUFFER_HEIGHT_OES, &backingHeight2);
NSInteger x = 0, y = 0, width2 = backingWidth2, height2 = backingHeight2;
NSInteger dataLength = width2 * height2 * 4;
GLubyte *data = (GLubyte*)malloc(dataLength * sizeof(GLubyte));
// Read pixel data from the framebuffer
glPixelStorei(GL_PACK_ALIGNMENT, 4);
glReadPixels(x, y, width2, height2, GL_RGBA, GL_UNSIGNED_BYTE, data);
// Create a CGImage with the pixel data
// If your OpenGL ES content is opaque, use kCGImageAlphaNoneSkipLast to ignore the alpha channel
// otherwise, use kCGImageAlphaPremultipliedLast
CGDataProviderRef ref = CGDataProviderCreateWithData(NULL, data, dataLength, NULL);
CGColorSpaceRef colorspace = CGColorSpaceCreateDeviceRGB();
CGImageRef iref = CGImageCreate(width2, height2, 8, 32, width2 * 4, colorspace, kCGBitmapByteOrder32Big | kCGImageAlphaPremultipliedLast,
ref, NULL, true, kCGRenderingIntentDefault);
// OpenGL ES measures data in PIXELS
// Create a graphics context with the target size measured in POINTS
NSInteger widthInPoints, heightInPoints;
if (NULL != UIGraphicsBeginImageContextWithOptions) {
// On iOS 4 and later, use UIGraphicsBeginImageContextWithOptions to take the scale into consideration
// Set the scale parameter to your OpenGL ES view's contentScaleFactor
// so that you get a high-resolution snapshot when its value is greater than 1.0
CGFloat scale = self.contentScaleFactor;
widthInPoints = width2 / scale;
heightInPoints = height2 / scale;
UIGraphicsBeginImageContextWithOptions(CGSizeMake(widthInPoints, heightInPoints), NO, scale);
}
else {
// On iOS prior to 4, fall back to use UIGraphicsBeginImageContext
widthInPoints = width2;
heightInPoints = height2;
UIGraphicsBeginImageContext(CGSizeMake(widthInPoints, heightInPoints));
}
CGContextRef cgcontext = UIGraphicsGetCurrentContext();
// UIKit coordinate system is upside down to GL/Quartz coordinate system
// Flip the CGImage by rendering it to the flipped bitmap context
// The size of the destination area is measured in POINTS
CGContextSetBlendMode(cgcontext, kCGBlendModeCopy);
CGContextDrawImage(cgcontext, CGRectMake(0.0, 0.0, widthInPoints, heightInPoints), iref);
// Retrieve the UIImage from the current context
UIImage *image = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
// Clean up
free(data);
CFRelease(ref);
CFRelease(colorspace);
CGImageRelease(iref);
return image;
}
Method to flip the image vertically:
- (UIImage *)flipImageVertically:(UIImage *)originalImage
{
UIImageView *tempImageView = [[UIImageView alloc] initWithImage:originalImage];
UIGraphicsBeginImageContext(tempImageView.frame.size);
CGContextRef context = UIGraphicsGetCurrentContext();
CGAffineTransform flipVertical = CGAffineTransformMake(
1, 0, 0, -1, 0, tempImageView.frame.size.height
);
CGContextConcatCTM(context, flipVertical);
[tempImageView.layer renderInContext:context];
UIImage *flippedImage = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
//[tempImageView release];
return flippedImage;
}

UIScrollview changes UIButton's image quality on zoom out

I've got a large display area that can be panned and zoomed to view different objects. The problem that I'm running into is that the quality of the PNG images UIButton becomes somewhat degraded if I'm zoomed out (however it is back to normal when I zoom back in to 100%). It almost looks as if the image becomes oversharpened. Is this something that I'm going to have to live with, or is there a way to get rid of this grainy edge effect? The aspect ratio of the images are always 1:1, by the way.
I was able to solve this by using the answer found here in my scrollViewDidEndZooming method. Here is my code:
Resize function
- (UIImage *)resizeImage:(UIImage*)image newSize:(CGSize)newSize {
CGRect newRect = CGRectIntegral(CGRectMake(0, 0, newSize.width, newSize.height));
CGImageRef imageRef = image.CGImage;
UIGraphicsBeginImageContextWithOptions(newSize, NO, 0);
CGContextRef context = UIGraphicsGetCurrentContext();
// Set the quality level to use when rescaling
CGContextSetInterpolationQuality(context, kCGInterpolationHigh);
CGAffineTransform flipVertical = CGAffineTransformMake(1, 0, 0, -1, 0, newSize.height);
CGContextConcatCTM(context, flipVertical);
// Draw into the context; this scales the image
CGContextDrawImage(context, newRect, imageRef);
// Get the resized image from the context and a UIImage
CGImageRef newImageRef = CGBitmapContextCreateImage(context);
UIImage *newImage = [UIImage imageWithCGImage:newImageRef];
CGImageRelease(newImageRef);
UIGraphicsEndImageContext();
return newImage;
}
ScrollView Method
(Widget is a UIViewController subclass which contains a button and a "widgetImage" which stores the full resolution of the image that the button should display)
- (void)scrollViewDidEndZooming:(UIScrollView *)scrollView withView:(UIView *)view atScale:(float)scale
{
for(Widget *theWidget in widgets){
UIImage *newScaledImage = [self resizeImage:theWidget.widgetImage newSize:CGSizeMake(theWidget.view.frame.size.width * scale, theWidget.view.frame.size.height * scale)];
[theWidget.widgetButton setImage:newScaledImage forState:UIControlStateNormal];
// theWidget.widgetButton.currentImage = newScaledImage;
}
}

Creating a gradient fill for text using [UIColor colorWithPatternImage:]

I want to create a gradient for the fill color of my text. Currently I am doing it by setting the color of a UILabel's text as
UIImage *image = [UIImage imageNamed:#"GradientFillImage.png"];
myLabel.textColor = [UIColor colorWithPatternImage:image];
Where GradientFillImage.png is a simple image file with a linear gradient painted on it.
This works fine until I want to resize the font. Since the image file is of constant dimensions and does not resize when I resize the font, the gradient fill for the font gets messed up.
How do I create a custom size pattern image and apply it as a fill pattern for text?
I've just finished a UIColor class extension that makes this a 1 line + block thing.
https://github.com/bigkm/UIColor-BlockPattern
CGRect rect = CGRectMake(0.0,0.0,10.0,10.0);
[UIColor colorPatternWithSize:rect.size andDrawingBlock:[[^(CGContextRef c) {
UIImage *image = [UIImage imageNamed:#"FontGradientPink.png"];
CGContextDrawImage(context, rect, [image CGImage]);
} copy] autorelease]];
Ok, I figured it out. Basically, we can override drawRectInText and use our own pattern to color the fill. The advantage of doing this is that we can resize the image into our pattern frame.
First we create a CGPattern object and define a callback to draw the pattern. We also pass the size of the label as a parameter in the callback. We then use the pattern that is drawn in the callback and set it as the fill color of the text:
- (void)drawTextInRect:(CGRect)rect
{
//set gradient as a pattern fill
CGRect info[1] = {rect};
static const CGPatternCallbacks callbacks = {0, &drawImagePattern, NULL};
CGAffineTransform transform = CGAffineTransformMakeScale(1.0, -1.0);
CGPatternRef pattern = CGPatternCreate((void *) info, rect, transform, 10.0, rect.size.height, kCGPatternTilingConstantSpacing, true, &callbacks);
CGColorSpaceRef patternSpace = CGColorSpaceCreatePattern(NULL);
CGFloat alpha = 1.0;
CGColorRef patternColorRef = CGColorCreateWithPattern(patternSpace, pattern, &alpha);
CGColorSpaceRelease(patternSpace);
CGPatternRelease(pattern);
self.textColor = [UIColor colorWithCGColor:patternColorRef];
self.shadowOffset = CGSizeZero;
[super drawTextInRect:rect];
}
The callback draws the image into the context. The image is resized as per the frame size that is passed into the callback.
void drawImagePattern(void *info, CGContextRef context)
{
UIImage *image = [UIImage imageNamed:#"FontGradientPink.png"];
CGImageRef imageRef = [image CGImage];
CGRect *rect = info;
CGContextDrawImage(context, rect[0], imageRef);
}

Showing UIBezierPath on view

In one of my methods i have this code:
-(void)myMethod {
UIBezierPath *circle = [UIBezierPath
bezierPathWithOvalInRect:CGRectMake(75, 100, 200, 200)];
}
How do i get it to show on the view?
I tried addSubview but it gave me an incompatible type error because its expecting a UIView.
I'm sure this must be simple.
Thanks
Just thought I'd add that you don't have to necessarily draw this in a UIView's "drawRect:" method. You can draw it anywhere you'd like to provided you do it inside of a UIGraphics image context. I do this all of the time when I don't want to create a subclass of UIView. Here's a working example:
UIBezierPath *circle = [UIBezierPath
bezierPathWithOvalInRect:CGRectMake(75, 100, 200, 200)];
//you have to account for the x and y values of your UIBezierPath rect
//add the x to the width (75 + 200)
//add the y to the height (100 + 200)
UIGraphicsBeginImageContext(CGSizeMake(275, 300));
//this gets the graphic context
CGContextRef context = UIGraphicsGetCurrentContext();
//you can stroke and/or fill
CGContextSetStrokeColorWithColor(context, [UIColor blueColor].CGColor);
CGContextSetFillColorWithColor(context, [UIColor lightGrayColor].CGColor);
[circle fill];
[circle stroke];
//now get the image from the context
UIImage *bezierImage = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
UIImageView *bezierImageView = [[UIImageView alloc]initWithImage:bezierImage];
Now just add the UIImageView as a subview.
Also, you can use this for other drawing too. Again, after a little bit of setup, it works just like the drawRect: method.
//this is an arbitrary size for example
CGSize aSize = CGSizeMake(50.f, 50.f);
//this can take any CGSize
//it works like the frame.size would in the drawRect: method
//in the way that it represents the context's size
UIGraphicsBeginImageContext(aSize);
//this gets the graphic context
CGContextRef context = UIGraphicsGetCurrentContext();
//you can do drawing just like you would in the drawRect: method
//I am drawing a square just for an example to show you that you can do any sort of drawing in here
CGContextMoveToPoint(context, 0.f, 0.f);
CGContextAddLineToPoint(context, aSize.width, 0.f);
CGContextAddLineToPoint(context, aSize.width, aSize.height);
CGContextAddLineToPoint(context, 0.f, aSize.height);
CGContextClosePath(context);
//you can stroke and/or fill
CGContextSetStrokeColorWithColor(context, [UIColor blueColor].CGColor);
CGContextSetFillColorWithColor(context, [UIColor lightGrayColor].CGColor);
CGContextDrawPath(context, kCGPathFillStroke);
//now get the image from the context
UIImage *squareImage = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
UIImageView *squareImageView = [[UIImageView alloc]initWithImage:squareImage];
Edit: One thing I should add is that for any modern day drawing of this kind, you should be swapping out
UIGraphicsBeginImageContext(size);
for
UIGraphicsBeginImageContextWithOptions(size, opaque, scale);
This will draw your graphics correctly for retina and non retina displays.
FYI, UIGraphicsBeginImageContext(size) is equivalent to UIGraphicsBeginImageContextWithOptions(size, FALSE, 1.f) which is fine for none retina displays that may have some transparency.
However, if you don't need transparency, it is more optimized to pass in TRUE for the opaque argument.
The safest and recommended way of drawing is to pass in [[UIScreen mainScreen]scale] as the scale argument.
So for the example(s) above, you would use this instead:
UIGraphicsBeginImageContextWithOptions(aSize, FALSE, [[UIScreen mainScreen] scale]);
For more info, check out Apple's docs.
You can draw it using either fill or stroke methods for example in custom view's drawInRect: implementation:
- (void)drawRect:(CGRect)rect {
// Drawing code
UIBezierPath *circle = [UIBezierPath
bezierPathWithOvalInRect:CGRectMake(75, 100, 200, 200)];
[circle fill];
}
You can also add UIBezierPath to UIView without subclassing by using a CAShapeLayer.
For example, to add your path as a 3pt white line centered in a UIView:
UIBezierPath *mybezierpath = [UIBezierPath
bezierPathWithOvalInRect:CGRectMake(0, 0, 100, 100)];
CAShapeLayer *lines = [CAShapeLayer layer];
lines.path = mybezierpath.CGPath;
lines.bounds = CGPathGetBoundingBox(lines.path);
lines.strokeColor = [UIColor whiteColor].CGColor;
lines.fillColor = [UIColor clearColor].CGColor; /*if you just want lines*/
lines.lineWidth = 3;
lines.position = CGPointMake(self.myview.frame.size.width/2.0, self.myview.frame.size.height/2.0);
lines.anchorPoint = CGPointMake(.5, .5);
[self.myview.layer addSublayer:lines];
Drawing is the exclusive provision of views. Make a custom view, give it your path, and implement the view's drawRect: method to fill and/or stroke the path.
In Swift 2.0:
let path = UIBezierPath()
let p1 = CGPointMake(0,self.view.frame.height/2)
let p3 = CGPointMake(self.view.frame.width,self.view.frame.height/2)
path.moveToPoint(p1)
path.addQuadCurveToPoint(p3, controlPoint: CGPoint(x: self.view.frame.width/2, y: 0))
let line = CAShapeLayer()
line.path = path.CGPath;
line.strokeColor = UIColor.blackColor().CGColor
line.fillColor = UIColor.redColor().CGColor
view.layer.addSublayer(line)