Shadow at the top of a Cell UITableCellView - iphone

I wondered if anyone knows how to get a shadaow effect like the one in things as per the screenshot. To me it looks like the shadow effect is created by having a shadow at the bottom of the cell above and the top of the cell below.
I can create the one from the cell above using the code below but can't figure out how to do it on the cell underneath as it doesn't get shown it's as if the cells are rendered in reverse order in terms of the z-index.
self.layer.shadowOffset = CGSizeMake(0, 2);
self.layer.shadowColor = [[UIColor blackColor] CGColor];
self.layer.shadowRadius = 2;
self.layer.shadowOpacity = 0.5;
CGFloat top = self.layer.bounds.origin.y;
CGFloat left = self.layer.bounds.origin.x;
CGFloat width = self.layer.bounds.size.width;
CGRect shadowFrame = CGRectMake(left, top, width, 44);
CGPathRef shadowPath = [UIBezierPath bezierPathWithRect:shadowFrame].CGPath;
self.layer.shadowPath = shadowPath;
Any suggestions much appreciated.
Things http://www.purplesmash.com/images/Things.jpg

Just create hollow rectangle while drawing with CoreGraphics (align it exactly that hollow part cover your cell visible view) and set shadow for context - this will save performance for you.
UPDATE:
I've tried this inside my cell drawRect: method
// Creating path which will hold our hollow rectangle
CGMutablePathRef path = CGPathCreateMutable();
CGPathAddRect(path, NULL, CGRectMake(-8.0f, -8.0f, 336.0f, 96.0f));
CGPathAddRect(path, NULL, CGRectMake(-5.0f, 0.0f, 330.0f, 80.0f));
// Saving current graphics context state
CGContextSaveGState(context);
// Configuring shadow
CGContextSetShadowWithColor(context, CGSizeMake(0.0f, 0.0f), 6.0f,
[[UIColor blackColor] CGColor]);
// Adding our path
CGContextAddPath(context, path);
// Configure hollow rectangle fill color
CGContextSetRGBFillColor(context, 1.0, 1.0, 1.0, 1.0);
// Fill rectangle and keep hollow part transparent
CGContextEOFillPath(context);
// Restore graphics context
CGContextRestoreGState(context);
Of course additional improvement will be pre-calculate CGMutablePathRef path somewhere in initialization or in this method by condition if(path == NULL). Colors can be retained too. If this should be last row of your cell update, than maybe you don't event need to save context state.

You probably need to do this by drawing the shadows as part of the checked cell instead of setting the shadow properties on the surrounding cells.
I'd do it by adding one or two CAGradientLayers as children of the checked cell's contentView.layer.

I have edited this in light of the suggestion from moonlight. I put that code into a method addInnerTopShadow when a cell needs that I call the method. I have added another method addInnerBottomShadow which puts in the shadow at the bottom.
I call these methods in the drawRect method and when I want to change between the states I call the method:
[cell setNeedsDisplay];
This allows me to toggle the state of the cell without doing things like
[self.tableView reloadData];
As the methods suggest I have outer shadow methods that put a shadow on the first and last cells but that's another issue and has been answered many times. I now have my app working exactly how I want. So thanks to Rob and Moonlight.
-(void)addInnerBottomShadow
{
CGContextRef context = UIGraphicsGetCurrentContext();
// Creating path which will hold our hollow rectangle
CGMutablePathRef path = CGPathCreateMutable();
CGPathAddRect(path, NULL, CGRectMake(0, 44, 480, 80));
CGPathAddRect(path, NULL, CGRectMake(0, 54, 480, 96));
// Saving current graphics context state
CGContextSaveGState(context);
// Configuring shadow
CGContextSetShadowWithColor(context, CGSizeMake(0.0f, 0.0f), 6.0f, [[UIColor blackColor] CGColor]);
// Adding our path
CGContextAddPath(context, path);
// Configure hollow rectangle fill color
CGContextSetRGBFillColor(context, 1.0, 1.0, 1.0, 1.0);
// Fill rectangle and keep hollow part transparent
CGContextEOFillPath(context);
CGContextClipToRect(context, self.bounds);
// Restore graphics context
CGContextRestoreGState(context);
}
-(void)addInnerTopShadow
{
CGContextRef context = UIGraphicsGetCurrentContext();
CGMutablePathRef path = CGPathCreateMutable();
CGPathAddRect(path, NULL, CGRectMake(-8.0f, -8.0f, 336.0f, 96.0f));
CGPathAddRect(path, NULL, CGRectMake(-5.0f, 0.0f, 330.0f, 80.0f));
// Saving current graphics context state
CGContextSaveGState(context);
// Configuring shadow
CGContextSetShadowWithColor(context, CGSizeMake(0.0f, 0.0f), 7.0f, [[UIColor blackColor] CGColor]);
// Adding our path
CGContextAddPath(context, path);
// Configure hollow rectangle fill color
CGContextSetRGBFillColor(context, 1.0, 1.0, 1.0, 1.0);
// Fill rectangle and keep hollow part transparent
CGContextEOFillPath(context);
CGContextClipToRect(context, self.bounds);
// Restore graphics context
CGContextRestoreGState(context);
}

Related

External Fill Color in iOS

I have two rectangles (two closed sub cgpaths).
Rectangle B is small and is present inside Rectangle A. All edges within it.
Is there a direct way to fill color area external to the rectangle B.
CAShapeLayer fillExternalColor something like that? If not a direct way, how to do this programmatically?
A - Purple color
B - Yellow color
So I tried drawing A and then drawing B. I wanted B to be of clear color (for now I put Yellow) but then I see purple color of A..
I found CGRectIntersection method that gives AnB and CGRectUnion method that gives AuB.
Is there a method that gives the rest of the area which is AuB - AnB?
You are using a CAShapeLayer. If your fillColor and your strokeColor are both opaque (alpha 1.0), you can simply set the layer's backgroundColor to fill those pixels that are within the layer's bounds but outside of its stroked and filled path.
My test code:
#implementation ViewController {
CAShapeLayer *layer;
}
- (void)viewDidLoad {
[super viewDidLoad];
layer = [CAShapeLayer layer];
layer.path = [UIBezierPath bezierPathWithOvalInRect:CGRectMake(50, 50, 250, 250)].CGPath;
layer.fillColor = [UIColor yellowColor].CGColor;
layer.strokeColor = [UIColor whiteColor].CGColor;
layer.lineWidth = 4;
layer.backgroundColor = [UIColor purpleColor].CGColor;
[self.view.layer addSublayer:layer];
}
- (void)viewDidLayoutSubviews {
layer.frame = self.view.bounds;
}
#end
Result:
I wanted to add red border inner rectangle on UIImage with masked outer part.
I came through this page. The following code is using CGContextEOFillPath can be helpful to others like me. (Some of the code is gathered from other pages.)
-(UIImage ) imageByDrawingBorderRectOnImage:(UIImage )image theRect:(CGRect)theRect
{
// begin a graphics context of sufficient size
UIGraphicsBeginImageContext(image.size);
// draw original image into the context
[image drawAtPoint:CGPointZero];
// get the context for CoreGraphics
CGContextRef ctx = UIGraphicsGetCurrentContext();
// set stroking color and to draw rect
[[UIColor redColor] setStroke];
// drawing with a red stroke color
CGContextSetRGBStrokeColor(ctx, 1.0, 0.0, 0.0, 1.0);
// the line width to 3
CGContextSetLineWidth(ctx, 3.0);
// Add Stroke Rectangle,
CGContextStrokeRect(ctx, theRect);
// Now draw fill outside part with partial alpha gray color
// drawing with a gray stroke color
CGMutablePathRef aPath = CGPathCreateMutable();
// outer rectangle
CGRect rectangle = CGRectMake( 0, 0, image.size.width, image.size.height);
CGPathAddRect(aPath, nil, rectangle);
// innter rectangle
CGPathAddRect(aPath, nil, theRect);
// set gray transparent color
CGContextSetFillColorWithColor(ctx, [UIColor colorWithRed:0.75 green:0.75 blue:0.75 alpha:0.5].CGColor);
// add the path to Context
CGContextAddPath(ctx, aPath);
// This method uses Even-Odd Method to draw in outer rectangle
CGContextEOFillPath(ctx);
// make image out of bitmap context
UIImage *retImage = UIGraphicsGetImageFromCurrentImageContext();
// free the context
UIGraphicsEndImageContext();
return retImage;
}
Regards.
Assuming A is the bigger shape, B is the smaller, inner shape, and bounds refers to the containing rect of A (probably the bounds of the view)
Clip shape B to the context (-addClip should do it)
CGContextClearRect the bounds
Fill shape A
Edit, found the source of this code
Given HoleView : UIView you must set:
self.opaque = NO;
self.backgroudColor = [UIColor clearColor];
and in drawRect:
[[UIColor purpleColor] setFill];
UIRectFill(A);
CGRect gapRectIntersection = CGRectIntersection(B, A);
[[UIColor clearColor] setFill];
UIRectFill(gapRectIntersection);
kCAFillRuleEvenOdd
Specifies the even-odd winding rule. Count the total number of path crossings. If the number of crossings is even, the point is outside the path. If the number of crossings is odd, the point is inside the path and the region containing it should be filled.
Available in OS X v10.6 and later.
Declared in CAShapeLayer.h.
Refer to :CAShapeLayer Class reference

drawing rectangle on button click in viewcontroller class in objective c IOS5

simply I am beginner in developing on ipad and I need to draw rectangle at point x,y with width and height when i clicked or touched button .
I searched on google but i didn't find anything working in button handler
Create rectangleButton in viewDidLoad method and write -(void)rectangleButtonSelected method in your ViewController.m. And also create class RectangleView of UIView.
-(void)rectangleButtonSelected{
RectangleView *temp = [[RectangleView alloc] initWithFrame:CGRectMake(0, 0, 60, 40)];
temp.center = CGPointMake(arc4random()%100, arc4random()%200);
NSLog(#"The Main center Point : %f %f",temp.center.x,temp.center.y);
[self.view addSubview:temp];
}
Implement - (void)drawRect:(CGRect)rect method in RectanglerView.m
- (void)drawRect:(CGRect)rect
{
// Drawing code
context =UIGraphicsGetCurrentContext();
CGContextSetRGBStrokeColor(context, 1.0, 1.0, 1.0, 1.0);
// And draw with a blue fill color
CGContextSetRGBFillColor(context, 0.0, 0.0, 1.0, 1.0);
// Draw them with a 2.0 stroke width so they are a bit more visible.
CGContextSetLineWidth(context, 2.0);
CGContextAddRect(context, self.bounds);
CGContextStrokePath(context);
// Close the path
CGContextClosePath(context);
// Fill & stroke the path
CGContextDrawPath(context, kCGPathFillStroke);
}
I hope it will be helpful to you
You actually need to do this with state. There's only one place you're allowed to do drawing, and that's in drawRect:. So, when the user clicks the button, you need to set some instance variable, like _isShowingRectangle or something, then call setNeedsDisplay on your custom UIView where you're doing your drawing.
Then, in your custom view's drawRect:, you can check if that state variable is set, and draw (or not draw) the rectangle. The code for drawing depends on which graphics layer you're using, but it's probably going to be something like
CGContextRef ctxt = UIGraphicsGetCurrentContext();
CGContextSetStrokeColorWithColor(ctxt,[[UIColor blackColor] CGColor]);
CGContextSetLineWidth(ctxt,3.0);
CGContextStrokeRect(ctxt,CGRectMake(10,20,100,50));

iPhone Quartz Drawing Eraser

I am trying to make an iPhone application with erasing. I am running into 2 problems, if you have a solution for either one please answer this. I would like to erase part of an image.
1) I am currently just clearing the rect but it has a square edge. I would like it to be round, I have previously tried translating but this does not work. I also need it to translate/rotate as few times as possible to maintain the same performance.
2) In addition I wanted to know if there are any other ways of erasing. When erasing fast it is erasing ever 1/2 inch. Is there a way to stroke a path and clear the rect or something? Sorry if this is hard to understand.
CGRect circleRect = CGRectMake([touch CGPointValue].x, [touch CGPointValue].y, 25, 25);
CGContextClearRect(currentContext,circleRect);
This code should do what you're looking for:
CGContextRef context = UIGraphicsGetCurrentContext();
CGContextSetLineCap(context, kCGLineCapRound);
CGContextSetLineWidth(context, self.strokeWidth);
CGContextSetBlendMode(context, kCGBlendModeClear);
CGContextSetStrokeColorWithColor(context, [[UIColor clearColor] CGColor]);
CGContextBeginPath(context);
CGContextMoveToPoint(context, lastPoint.x, lastPoint.y);
CGContextAddLineToPoint(context, currentPoint.x, currentPoint.y);
CGContextStrokePath(context);
CGContextFlush(context);
The key points are
1) CGContextSetLineCap(context, kCGLineCapRound), which makes it round
2) CGContextSetBlendMode(context, kCGBlendModeClear) which clears the context.
I realize this is an older question but I thought I would expand on Eric Reids answer as I was trying to use his example outside of the drawRect method and had to modify it to get it to work with a context I created in a 'touchesMoved' method in a UIView subclass.
I call this method from 'touchesMoved' and pass it the CGPoint of the touch in the view I'm drawing in.
-(void) processEraseAtPoint:(CGPoint)point
{
// setup a context with the size of our canvas view (the canvas view is the UIView instance I'm drawing into)
UIGraphicsBeginImageContext(self.canvasView.bounds.size);
// get a reference to the context we just created
CGContextRef context = UIGraphicsGetCurrentContext();
// draw the image we want to edit into this context (this is the image containing the drawing I want to erase part of)
[self.canvasView.incrementalImage drawAtPoint:CGPointZero];
// set our context options
CGContextSetLineCap(context, kCGLineCapRound);
CGContextSetLineWidth(context, self.canvasView.settings.brushDiameter);
CGContextSetBlendMode(context, kCGBlendModeClear);
// make the color clear since we're erasing
CGContextSetStrokeColorWithColor(context, [[UIColor clearColor] CGColor]);
// start our path in this context
CGContextBeginPath(context);
// set our first point
CGContextMoveToPoint(context, lastTouch.x, lastTouch.y);
// draw from our last point to this point
CGContextAddLineToPoint(context, point.x, point.y);
// stroke this path (in this case it's clear so it will erase what's there)
CGContextStrokePath(context);
// set our incrementalImage in the canvasView with the updated image from this context
// Note that in the canvasView 'drawRect' method I am calling
// '[self.incrementalImage drawInRect:rect]', so this new image will get drawn
// in my canvasView when I call 'setNeedsDisplay'
self.canvasView.incrementalImage = UIGraphicsGetImageFromCurrentImageContext();
// cleanup our context
CGContextFlush(context);
UIGraphicsEndImageContext();
// set our last touch point for the next line segment
lastTouch = point;
// update our view
[self.canvasView setNeedsDisplay];
}

How to fill the shapes with color

I am new to Objective-C and iOS development. I have a view with some figures drawn by core drawing. Now I want to fill those shapes with color and I don't know the path or context of shape. Does Objective-C have any function like flood-fill or put-pixel so that by having only the stroke color I can fill any shape inside my view.
-(void)drawRect:(CGRect)rect
{
CGContextRef context = UIGraphicsGetCurrentContext();
CGContextSetLineWidth(context, 4.0);
CGColorSpaceRef colorspace = CGColorSpaceCreateDeviceRGB();
CGFloat components[] = {1.0, 0.0, 0.0, 1.0};
CGColorRef color = CGColorCreate(colorspace, components);
CGContextSetStrokeColorWithColor(context, color);
CGContextMoveToPoint(context, 50, 0);
CGContextAddLineToPoint(context, 0,320);
CGContextStrokePath(context);
CGColorSpaceRelease(colorspace);
CGColorRelease(color);
CGContextSetLineWidth(context, 2.0);
CGContextSetStrokeColorWithColor(context, [UIColor blueColor].CGColor);
CGContextSetRGBFillColor(context, 0, 255, 0, 1.0);
CGContextMoveToPoint(context, 100, 100);
CGContextAddLineToPoint(context, 150, 150);
CGContextAddLineToPoint(context, 100, 200);
CGContextAddLineToPoint(context, 50, 150);
CGContextAddLineToPoint(context, 100, 100);
CGContextStrokePath(context);
CGContextSetLineWidth(context, 2.0);
CGContextSetStrokeColorWithColor(context, [UIColor blueColor].CGColor);
CGRect rectangle = CGRectMake(60,170,200,80);
CGContextAddEllipseInRect(context, rectangle);
CGContextStrokePath(context);
}
This will make a circle and a square with some common region. I want a particular region to fill with color when a user taps that region.
So you are looking for flood fill in Objective C.
This is my implementation of Scan Line Flood Fill Algorithm.
Github : UIImageScanlineFloodfill
If you want to learn basic of flood fill:
Lode's Computer Graphics Tutorial Flood Fill
I hope this will help you.
Put your drawing code in the question and I can give you a specific answer.
Normally you just need to set a fill color using
[[UIColor redColor] setFill];
And any shapes you draw your core graphics will be filled with that color automatically.
Try this command:-
CGContextSetStrokeColorWithColor(context, [UIColor blueColor].CGColor);
Core Graphics is closely tied to UIView and its drawRect: method and has a C interface. As you point out, you always draw in the current graphics context. I can think of 2 approaches: (1) When the user taps myView, set a property like myView.pointTapped, and in drawRect: find the shape to fill, set a fill color, and fill the closed path using GGGeometry methods.
There is an objective-C alternative: (2) Take a look at UIBezierPath. It's not as comprehensive as drawing in Core Graphics but it can be used in your ViewController implementation.

How to draw a line with a custom style using Core Graphics?

I'm currently drawing a line using Core Graphics. It's really bare bones and simple.
- (void)drawRect:(CGRect)rect {
CGContextRef c = UIGraphicsGetCurrentContext();
CGFloat red[4] = {1.0f, 0.0f, 0.0f, 1.0f};
CGContextSetStrokeColor(c, red);
CGContextBeginPath(c);
CGContextMoveToPoint(c, 5.0f, 5.0f);
CGContextAddLineToPoint(c, 300.0f, 600.0f);
CGContextSetLineWidth(c, 25);
CGContextSetLineCap(c, kCGLineCapRound);
CGContextStrokePath(c);
}
This works well. Let's say that we wanted to draw a custom style line. Say we wanted to imitate the style of a crayon for example. And that the designer handed your crayon style images: http://imgur.com/a/N40ig
To do accomplish this effect I think I need to do something like this:
Create a special colored versions of crayonImage1-crayonImage4
Every time you add a line to line you use one of the crayonImages
You alternate the crayonImages every time you draw a point.
Step 1 makes sense. I can use the following method:
- (UIImage *)image:(UIImage *)img withColor:(UIColor *)color {
// begin a new image context, to draw our colored image onto
UIGraphicsBeginImageContext(img.size);
// get a reference to that context we created
CGContextRef context = UIGraphicsGetCurrentContext();
// set the fill color
[color setFill];
// translate/flip the graphics context (for transforming from CG* coords to UI* coords
CGContextTranslateCTM(context, 0, img.size.height);
CGContextScaleCTM(context, 1.0, -1.0);
// set the blend mode to color burn, and the original image
CGContextSetBlendMode(context, kCGBlendModeColorBurn);
CGRect rect = CGRectMake(0, 0, img.size.width, img.size.height);
CGContextDrawImage(context, rect, img.CGImage);
// set a mask that matches the shape of the image, then draw (color burn) a colored rectangle
CGContextClipToMask(context, rect, img.CGImage);
CGContextAddRect(context, rect);
CGContextDrawPath(context,kCGPathFill);
// generate a new UIImage from the graphics context we drew onto
UIImage *coloredImg = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
//return the color-burned image
return coloredImg;
}
I'm unsure how I can complete steps 2 and 3. Is there an API in CoreGraphics for setting an image as the point of line? If so what is it and how can I use it?
Thanks in advance,
-David
Start with the following example: http://www.ifans.com/forums/showthread.php?t=132024
But for brushes, don't draw a line. Simply draw the brush image using CGContextDrawImage.
Basically, you simply draw an image for every touch.