Is there any way we can make only the selected area of a superview transparent? I have a UIView with black (alpha 0.5) background color. I am putting some hollow circles on the UIView and want the underneath UIView to be transparent so that I could see through it. Any idea
- (id)initWithFrame:(CGRect)iFrame andHollowFrames:(NSArray *)iHollowFrames withRadius:(NSNumber *)iRadius {
if ((self = [super initWithFrame:iFrame]) != nil) {
self.hollowFrames = [[NSSet setWithArray:iHollowFrames] allObjects];
self.hollowCircleRadius = iRadius;
[self addShadowView];
}
return self;
}
- (void)addShadowView {
UIBezierPath *path = [UIBezierPath bezierPathWithRoundedRect:CGRectMake(0, 0, self.bounds.size.width, self.bounds.size.height) cornerRadius:0];
for (NSValue *point in self.hollowFrames) {
UIBezierPath *circlePath = [UIBezierPath bezierPathWithRoundedRect:CGRectMake(point.CGPointValue.x - self.hollowCircleRadius.floatValue, point.CGPointValue.y - self.hollowCircleRadius.floatValue, 2.0 * self.hollowCircleRadius.floatValue, 2.0 * self.hollowCircleRadius.floatValue) cornerRadius:self.hollowCircleRadius.floatValue];
[path appendPath:circlePath];
}
[path setUsesEvenOddFillRule:YES];
CAShapeLayer *fillLayer = [CAShapeLayer layer];
fillLayer.path = path.CGPath;
fillLayer.fillRule = kCAFillRuleEvenOdd;
fillLayer.fillColor = [UIColor blackColor].CGColor;
fillLayer.opacity = 0.5;
[self.layer addSublayer:fillLayer];
}
Here is a UIView subclass solution. In order for this to work you must leave the superviews backgroundColor property as nil witch is the default value. If this UIView-subclass is in the storyboard then make sure you set the background color to "Clear color" in the attributes inspector.
- (void)drawRect:(CGRect)rect
{
CGContextRef ctx = UIGraphicsGetCurrentContext();
UIColor *blackBackgroundColor = [UIColor colorWithRed:0 green:0 blue:0 alpha:0.5];
CGContextSetFillColorWithColor(ctx, blackBackgroundColor.CGColor);
CGContextFillRect(ctx, rect);
CGRect transparentPart = CGRectMake(10, 10, 120, 80);
CGContextClearRect(ctx, transparentPart);
}
Related
In my app , I made a see through UIView by subclassing simple UIView's. However, If I try to do the same using UIVisualEffectView, I am not able to do it.
Here is what I am able to do using normal UIView:
When I use the UIVisualEffectView in place of green UIView,I cannot see the see through UIView , even though see through UIView is added to the UIVisualEffectView as subview.
Code:
- (void)drawRect:(CGRect)rect { //this is same for the UIVIew and for the UIVisualEffectView
[super drawRect:rect];
CGContextRef context = UIGraphicsGetCurrentContext();
// Clear any existing drawing on this view
// Remove this if the hole never changes on redraws of the UIView
CGContextClearRect(context, self.bounds);
// Create a path around the entire view
UIBezierPath *clipPath = [UIBezierPath bezierPathWithRect:self.bounds];
// Your transparent window. This is for reference, but set this either as a property of the class or some other way
CGRect transparentFrame;
// Add the transparent window
UIBezierPath *path = [UIBezierPath bezierPathWithRoundedRect:transparentFrame cornerRadius:5.0f];
[clipPath appendPath:path];
// NOTE: If you want to add more holes, simply create another UIBezierPath and call [clipPath appendPath:anotherPath];
// This sets the algorithm used to determine what gets filled and what doesn't
clipPath.usesEvenOddFillRule = YES;
// Add the clipping to the graphics context
[clipPath addClip];
// set your color
UIColor *tintColor = [UIColor greenColor];
// (optional) set transparency alpha
CGContextSetAlpha(context, 0.7f);
// tell the color to be a fill color
[tintColor setFill];
// fill the path
[clipPath fill];
}
Question: Why this didn't work with UIVisualEffectView ?
Add following global variables in your ViewController.h file-
CAShapeLayer *fillLayer;
UIVisualEffectView *overlayView;
Add following methods in your ViewController.m file-
-(void)addOverlay:(CGRect)rect{
float x = rect.origin.x;
float y = rect.origin.y;
UIBezierPath *path = [UIBezierPath bezierPathWithRoundedRect:CGRectMake(0, 0, self.view.bounds.size.width, self.view.bounds.size.height) cornerRadius:0];
UIBezierPath *circlePath = [UIBezierPath bezierPathWithRoundedRect:CGRectMake(x, y, rect.size.width, rect.size.height) cornerRadius:5];
[path appendPath:circlePath];
[path setUsesEvenOddFillRule:YES];
[self removeOverlay];
overlayView = [[UIVisualEffectView alloc] initWithFrame:CGRectMake(0, 0, self.view.bounds.size.width, self.view.bounds.size.height+64)];
overlayView.backgroundColor = [UIColor clearColor];
[self.view addSubview:overlayView];
fillLayer = [CAShapeLayer layer];
fillLayer.path = path.CGPath;
fillLayer.fillRule = kCAFillRuleEvenOdd;
fillLayer.fillColor = [UIColor colorWithRed:78/255.0 green:103/255.0 blue:135/255.0 alpha:1.0].CGColor;
fillLayer.opacity = 0.85;
[[UIApplication sharedApplication].keyWindow.layer addSublayer:fillLayer];
}
-(void)removeOverlay{
[overlayView removeFromSuperview];
[fillLayer removeFromSuperlayer];
}
and call it as -
[self addOverlay:rect];
I have a UIView I'm trying to put together which will be layered above another view. This new view needs to have a fully transparent hole in it. I've attached a screenshot of what it is I'm trying to accomplish (checkerboard pattern is the underlying UIView that will be adding this new UIView as a sublayer, red is a UIImage).
I have the following code that will render the black background with the hole in the center:
- (void)
drawRect:(CGRect)rect
{
CGRect boxRect = CGRectMake(_location.x - (kPointRadius/2), _location.y - (kPointRadius/2), kPointRadius, kPointRadius);
UIBezierPath *path = [UIBezierPath
bezierPathWithRoundedRect:CGRectMake(0, 0, self.layer.frame.size.width, self.layer.frame.size.height)
cornerRadius:0];
UIBezierPath *circlePath = [UIBezierPath
bezierPathWithRoundedRect:boxRect
cornerRadius:kPointRadius];
[path appendPath:circlePath];
[path setUsesEvenOddFillRule:YES];
CAShapeLayer *fillLayer = [CAShapeLayer layer];
fillLayer.path = path.CGPath;
fillLayer.fillRule = kCAFillRuleEvenOdd;
fillLayer.fillColor = [UIColor blackColor].CGColor;
fillLayer.borderWidth = 5.0;
fillLayer.borderColor = [UIColor redColor].CGColor;
fillLayer.opacity = 0.7;
[self.layer addSublayer:fillLayer];
}
However, when I add an image to that and use [[UIImage imageNamed:#"testimg" drawAtPoint:CGPointMake(x, y)]; to add the image, the image covers the hole.
Can anyone point me in the right direction here? I'm stumped.
EDIT: I'm now able to get it almost there. I can get everything I need EXCEPT the image layered on top of the black, 90% opaque background is also at 90% opacity.
CGRect boxRect = CGRectMake(
_location.x - (kPointRadius/2),
_location.y - (kPointRadius/2),
kPointRadius,
kPointRadius);
UIBezierPath *path = [UIBezierPath
bezierPathWithRoundedRect:CGRectMake(0, 0, self.layer.frame.size.width, self.layer.frame.size.height) cornerRadius:0];
UIBezierPath *circlePath = [UIBezierPath
bezierPathWithRoundedRect:boxRect
cornerRadius:kPointRadius];
[path appendPath:circlePath];
[path setUsesEvenOddFillRule:YES];
UIImage *image = [UIImage imageNamed:#"testimg"];
UIImageView *imageView = [[UIImageView alloc] initWithFrame:CGRectMake(13, 57, 350, 230)];
imageView.image = image;
CGRect r = CGRectMake(self.layer.frame.origin.x, self.layer.frame.origin.y, self.layer.frame.size.width, self.layer.frame.size.height);
UIGraphicsBeginImageContextWithOptions(r.size, NO, 0);
CGContextRef c = UIGraphicsGetCurrentContext();
CGContextAddPath(c, CGPathCreateCopy(path.CGPath));
CGContextEOClip(c);
CGContextFillRect(c, r);
UIImage* maskim = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
CALayer* mask = [CALayer layer];
mask.frame = r;
mask.contents = (id)maskim.CGImage;
imageView.layer.mask = mask;
self.layer.mask = mask;
self.layer.backgroundColor = [UIColor blackColor].CGColor;
self.layer.opacity = 0.8;
[self.layer addSublayer:imageView.layer];
EDIT: I'm now able to get it almost there. I can get everything I need EXCEPT the image layered on top of the black, 90% opaque background is also at 90% opacity.
Instead of setting its opacity, you could set the layer's background color to [UIColor colorWithWhite:0.0 alpha:0.9].
I have three buttons, all have different direction.
I have to connect them with a red line.
Just like Tic Tec Toc if game over than how to connect them with line:
How do I set line between them??
Or you can use this code..
UIView *lineView = [[UIView alloc] initWithFrame:CGRectMake(0, 200, self.view.bounds.size.width, 1)];
lineView.backgroundColor = [UIColor blackColor];
[self.view addSubview:lineView];
This is one way of drawing line :
Here you need to subclass UIView and then use CoreGraphics calls in the drawRect method:
- (void)drawRect:(CGRect)rect
{
CGContextRef context = UIGraphicsGetCurrentContext();
CGContextSetLineWidth(context, 4.0);
CGContextSetStrokeColorWithColor(context, [UIColor blueColor].CGColor);
CGContextMoveToPoint(context, 25, 25);
CGContextAddLineToPoint(context, 75, 75);
CGContextStrokePath(context);
}
Another way is using UIBezierPath as follows :
UIBezierPath *path = [UIBezierPath bezierPath];
[path moveToPoint:CGPointMake(10.0, 10.0)];
[path addLineToPoint:CGPointMake(100.0, 100.0)];
CAShapeLayer *shapeLayer = [CAShapeLayer layer];
shapeLayer.path = [path CGPath];
shapeLayer.strokeColor = [[UIColor blueColor] CGColor];
shapeLayer.lineWidth = 3.0;
shapeLayer.fillColor = [[UIColor clearColor] CGColor];
[self.view.layer addSublayer:shapeLayer];
I am trying to draw a CAShapeLayer in a UIView and update the strokeStart and strokeEnd in response to a changing variable. The shape layer is created and drawn on screen as it should, but I am not able to update it.
My code:
//drawing shapeLayer on screen
- (void)setFrame:(CGRect)frame
{
[super setFrame:frame];
shapeLayer = [CAShapeLayer layer];
UIBezierPath *variometerGuage = [UIBezierPath bezierPath];
[variometerGuage moveToPoint:CGPointMake(25, 5)];
[variometerGuage addLineToPoint:CGPointMake(25, 200)];
[shapeLayer setPath:variometerGuage.CGPath];
shapeLayer.strokeStart = 0;
shapeLayer.strokeEnd = .5;
shapeLayer.strokeColor = [UIColor colorWithWhite:0.5 alpha:1.0].CGColor;
shapeLayer.lineWidth = 10;
[shapeLayer setLineCap:kCALineCapButt];
[self.layer addSublayer:shapeLayer];
}
The following code is called from the View Controller. I know it is being executed, but the UIView is not updated.
- (void)updateVariometerGraphocsWithLift:(float)vario {
shapeLayer.strokeStart = vario; //vario being a number between 0 and 1
[shapeLayer setNeedsDisplay];
[self.layer addSublayer:shapeLayer];
[self.layer setNeedsDisplay];
[self.layer setNeedsLayout];
}
Any ideas?
Is it possible to draw the following in objective-c? I tried using the image, but It pixelates. So I figured it is best to draw it programatically. Can someone provide me some sample code to achieve this.
Thank you.
Use a CAShapeLayerand assign it a path describing your shape:
- (UIBezierPath *)createBubblePathInFrame:(CGRect) frame{
CGFloat arrowInset = 10;
CGFloat arrowHeight = 10;
CGFloat arrowWidth = 20;
UIBezierPath *path = [UIBezierPath bezierPath];
[path moveToPoint:CGPointMake(0, arrowHeight)];
[path addLineToPoint:CGPointMake(arrowInset, arrowHeight)];
[path addLineToPoint:CGPointMake(arrowInset+arrowWidth/2, 0)];
[path addLineToPoint:CGPointMake(arrowInset+arrowWidth, arrowHeight)];
[path addLineToPoint:CGPointMake(frame.size.width, arrowHeight)];
[path addLineToPoint:CGPointMake(frame.size.width, frame.size.height)];
[path addLineToPoint:CGPointMake(0, frame.size.height)];
[path addLineToPoint:CGPointMake(0, arrowHeight)];
return path;
}
Use it like this:
CAShapeLayer *shapelayer = [CAShapeLayer layer];
shapelayer.frame = CGRectMake(50, 50, 200, 100);
shapelayer.path = [self createBubblePathInFrame:shapelayer.bounds].CGPath;
shapelayer.fillColor = [UIColor grayColor].CGColor;
shapelayer.strokeColor = [UIColor redColor].CGColor;
shapelayer.lineWidth = 1;
[self.view.layer addSublayer:shapelayer];
Or you can draw it yourself in drawRect:
[[UIColor grayColor] setFill];
[bezierPath fill];
[[UIColor redColor] setStroke];
[bezierPath stroke];
You can use this as a triangle view:
#implementation Triangle
- (id)initWithFrame:(CGRect)frame
{
self = [super initWithFrame:frame];
if (self)
{
self.backgroundColor = [UIColor clearColor];
self.alpha = 0.75;
}
return self;
}
- (void)drawRect:(CGRect)rect
{
CGContextRef ctx = UIGraphicsGetCurrentContext();
CGContextBeginPath(ctx);
CGContextMoveToPoint(ctx, CGRectGetMinX(rect), CGRectGetMinY(rect)); // top left
CGContextAddLineToPoint(ctx, CGRectGetMaxX(rect), CGRectGetMinY(rect)); // top right
CGContextAddLineToPoint(ctx, CGRectGetMidX(rect), CGRectGetMaxY(rect)); // bottom mid
CGContextClosePath(ctx);
CGContextSetRGBFillColor(ctx, 25.0/255.0, 25.0/255.0, 25.0/255.0, 1.0);
CGContextFillPath(ctx);
}
#end
Then just subclass a UIView and add an instance of Triangle where appropriate (in your case on the top left corner).
For your purpose you also should rotate this triangle 180 degrees as the code above drwas a triangle that points downwards.