Hi I am doing the legend for the different polygon colors in a map, and I want to show a little square with the UIColor used for that certain item. I was thinking of using a UIImage and setting the background color to that color but I can't figure it out. What is the best way to go about this problem?
Thanks
If you need user interaction with this square than use UIView, in other case you need to use CAShapeLayer. There wont be any visual difference, but using layer is preferred if you have only show something without any interaction.
use [UIBezierPath bezierPathWithRect:(CGRect)rect]
and than with that path
CAShapeLayer *shapeLayer = [CAShapeLayer layer];
shapeLayer.path = [path CGPath];
shapeLayer.fillColor = [[UIColor clearColor] CGColor];
Add that CAShapeLayer to your view's layer:
[self.view.layer addSublayer:shapeLayer];
I want to draw a single path, which can overlap itself. What I want is like a snap of Moves below:
Can I achieve this just fill a single CGPathRef on iOS?
I created two paths, a gray one and red one below:
There are two overlaps on the gray line, one for itself and one for the red line. The red overlap, you can see it clearly, is above (or below) the gray one. But the gray overlap is just merged.
The Moves trace line is a single line, maybe is not implemented by a single path fill or stroke.
Here's my code:
[[UIColor colorWithWhite:0.0 alpha:0.3] setStroke];
CGFloat lineWidth = 10.0;
UIBezierPath *path = [UIBezierPath bezierPath];
path.lineWidth = lineWidth;
[path moveToPoint:CGPointMake(300, 50)];
[path addLineToPoint:CGPointMake(20, 400)];
[path addLineToPoint:CGPointMake(300, 400)];
[path addLineToPoint:CGPointMake(20, 50)];
[path stroke];
[[UIColor colorWithRed:1.0 green:0.5 blue:0.5 alpha:0.5] setStroke];
UIBezierPath *anotherPath = [UIBezierPath bezierPath];
anotherPath.lineWidth = lineWidth;
[anotherPath moveToPoint:CGPointMake(160, 50)];
[anotherPath addLineToPoint:CGPointMake(300, 200)];
[anotherPath stroke];
I have an issue regarding the section border. I have a UITableView and it is of type Grouped. I am trying to draw the border around the each section of the tableview. I am getting the section frame using the below code. Could please tell me how to draw the border around the UITableView section.
CGRect rect = [groupsTableView rectForSection:indexPath.section];
NSLog(#"%f %f %f %f",rect.origin.x,rect.origin.y,rect.size.width,rect.size.height);
I will recommend that you make a new TableView Cell and inside this newTableViewCell, load all the cells in section 2 then give border to newTableViewCell.
but if you don't wanna do that then you can use this code :
#property(strong,nonatomic) CAShapeLayer* borderPath;
-(void)viewDidLayoutSubviews{
[_borderPath removeFromSuperlayer];
UIView *viewToGiveBorder = [[UIView alloc]initWithFrame:sectionView.frame];
UIBezierPath *path = [UIBezierPath bezierPathWithRoundedRect:viewToGiveBorder.bounds byRoundingCorners:(UIRectCornerAllCorners) cornerRadii:CGSizeMake(5.0, 5.0)];
//apply path to shapelayer
_borderPath= [CAShapeLayer layer];
_borderPath.path = path.CGPath;
[_borderPath setFillColor:[UIColor clearColor].CGColor];
[_borderPath setStrokeColor:[UIColor colorWithRed: 0 green: 0 blue: 0].CGColor];
_borderPath.frame=sectionView.frame;
//add shape layer to view's layer
[[self.view layer] addSublayer:_borderPath];
}
self.myPath=[UIBezierPath bezierPathWithArcCenter:center
radius:200
startAngle:0
endAngle:180
clockwise:YES];
(This much I was able to get up running with some web searching).
I have this path. Now I want to fill the reverse of this path, so leaving this portion and filling everything else. How can I finish the coding? I don't have much info on this.
The problem
The area it is showing after using Cemal Answer previously it only showed a circle with red stroke.
Edit
- (id)initWithFrame:(CGRect)frame
{
self = [super initWithFrame:frame];
if (self) {
self.backgroundColor = [UIColor whiteColor];
self.punchedOutPath =
[UIBezierPath bezierPathWithOvalInRect:CGRectMake(50, 50, 400, 400)];
self.fillColor = [UIColor redColor];
self.alpha = 0.8;
}
return self;
}
- (void)drawRect:(CGRect)rect
{
[[self fillColor] set];
UIRectFill(rect);
CGContextRef ctx = UIGraphicsGetCurrentContext();
CGContextSetBlendMode(ctx, kCGBlendModeDestinationOut);
[[self punchedOutPath] fill];
CGContextSetBlendMode(ctx, kCGBlendModeNormal);
}
Use bezierPathByReversingPath. From the docs (iOS 6.0+ only):
Creates and returns a new bezier path object with the reversed contents of the current path.
so to reverse your path, you'd just:
UIBezierPath* aPath = [UIBezierPath bezierPathWithArcCenter:center
radius:200
startAngle:0
endAngle:180
clockwise:YES];
self.myPath = [aPath bezierPathByReversingPath];
Here's an alternative that doesn't require reversing the path at all.
You have a portion of a view you essentially want to "clip out":
Let's say you want the white area to be [UIColor whiteColor] with 75% alpha. Here's how you do it quickly:
You create a new UIView subclass.
This view has two properties:
#property (retain) UIColor *fillColor;
#property (retain) UIBezierPath *punchedOutPath;
You override its -drawRect: method to do this:
- (void)drawRect:(CGRect)rect {
[[self fillColor] set];
UIRectFill(rect);
CGContextRef ctx = UIGraphicsGetCurrentContext();
CGContextSetBlendMode(ctx, kCGBlendModeDestinationOut);
[[self punchedOutPath] fill];
CGContextSetBlendMode(ctx, kCGBlendModeNormal);
}
There's a caveat here: The fillColor of the view must not include the alpha component. So in your case, you'd want that to just be [UIColor whiteColor]. You then apply the alpha bit yourself by calling [myView setAlpha:0.75].
What's going on here: This is using a blend mode called "Destination Out". Mathematically it's defined as R = D*(1 - Sa), but in layman's terms it means "Destination image wherever destination image is opaque but source image is transparent, and transparent elsewhere."
So it's going to use the destination (i.e., what's already in the context) wherever the new stuff is transparent (i.e. outside of the bezier path), and then where the bezier path would be opaque, that stuff is going to become transparent. However, the destination stuff must already be opaque. If it's not opaque, the blending doesn't do what you want. This is why you have to provide an opaque UIColor and then do any transparency you want with the view directly.
I ran this myself, with these circumstances:
the window has a [UIColor greenColor] background
the fillColor is white
the punchedOutPath is a oval that's inset 10 points from the edges of the view.
the view has an alpha of 0.75
With the code above, I get this:
The interior is pure green, and the outside has the semi-transparent overlay.
Update
If your covering is an image, then you'll need to create a new image. But the principle is the same:
UIImage* ImageByPunchingPathOutOfImage(UIImage *image, UIBezierPath *path) {
UIGraphicsBeginImageContextWithOptions([image size], YES, [image scale]);
[image drawAtPoint:CGPointZero];
CGContextRef ctx = UIGraphicsGetCurrentContext();
CGContextSetBlendMode(ctx, kCGBlendModeDestinationOut);
[path fill];
UIImage *final = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
return final;
}
You would then take the result of this function and put it into a UIImageView.
You can put this into a single screen app into the view controller: It will make a yellow background view and a blue layer on top of it that has an oval region cut out by a mask.
- (void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
// create a yellow background
UIView *bg = [[UIView alloc] initWithFrame:self.view.bounds];
bg.backgroundColor = [UIColor yellowColor];
[self.view addSubview:bg];
// create the mask that will be applied to the layer on top of the
// yellow background
CAShapeLayer *maskLayer = [CAShapeLayer layer];
maskLayer.fillRule = kCAFillRuleEvenOdd;
maskLayer.frame = self.view.frame;
// create the paths that define the mask
UIBezierPath *maskLayerPath = [UIBezierPath bezierPath];
[maskLayerPath appendPath:[UIBezierPath bezierPathWithRect:CGRectInset(self.view.bounds, 20, 20)]];
// here you can play around with paths :)
// [maskLayerPath appendPath:[UIBezierPath bezierPathWithOvalInRect:(CGRect){{80, 80}, {140, 190}}]];
[maskLayerPath appendPath:[UIBezierPath bezierPathWithOvalInRect:(CGRect){{100, 100}, {100, 150}}]];
maskLayer.path = maskLayerPath.CGPath;
// create the layer on top of the yellow background
CALayer *imageLayer = [CALayer layer];
imageLayer.frame = self.view.layer.bounds;
imageLayer.backgroundColor = [[UIColor blueColor] CGColor];
// apply the mask to the layer
imageLayer.mask = maskLayer;
[self.view.layer addSublayer:imageLayer];
}
this might answer this question as well: UIBezierPath Subtract Path
I have two solution for you.
Draw this path on a CALayer. And use that CALayer as a mask layer for you actual CALayer.
Draw a rectangle with the sizes of you frame before adding arc.
UIBezierPath *path = [UIBezierPath bezierPathWithRect:view.frame];
[path addArcWithCenter:center
radius:200
startAngle:0
endAngle:2*M_PI
clockwise:YES];
I would use second solution. :)
I have a weird issue with some basic drawing code here:
The code for this is just the following in a for-loop, I just want to draw some vertical lines into the view:
UIBezierPath* verticalLine = [UIBezierPath bezierPath];
[verticalLine moveToPoint:CGPointMake(currentXPosition, 0)];
[verticalLine addLineToPoint:CGPointMake(currentXPosition, self.frame.size.height)];
[verticalLine closePath];
verticalLine.lineWidth = 1;
[[UIColor blackColor] setStroke];
[verticalLine stroke];
I can't imagine a reason for it. Can you?
Thanks in advance,
Christian
EDIT: Drawing horizontal lines works perfectly well, they have normal width and don't fade out.