iOS Draw a line above label - ios

I have a label in my view. Now I want to draw a line above the label, which means you can see the label is under the line.
So far I can draw a line using quartz2D but always under the label. Is there any way to solve my problems?

You can create a CAShapeLayer like this:
CAShapeLayer *lineLayer = [CAShapeLayer layer];
lineLayer.frame = self.label.bounds;
lineLayer.strokeColor = [UIColor redColor].CGColor;
CGRect rect = CGRectMake(0, CGRectGetMidY(lineLayer.bounds), lineLayer.bounds.size.width, 2);
lineLayer.path = [UIBezierPath bezierPathWithRect:rect].CGPath;
And then add it to the UILabel like this:
[self.label.layer addSublayer:lineLayer];

To be honest, the easiest thing to do is to create a 2x2 pixel image called line#2x.png, and have the bottom 2 pixels black, the top 2 transparent, then use it as the background image for an image view. Stretch the image view to whatever width you need by using it as a pattern image. The 1x image should be a 1x1px, all black.
UIView *lineView = [[UIView alloc] initWithFrame:frame]; // Whatever frame the line needs
// Add the line image as a pattern
UIColor *patternColor = [UIColor colorWithPatternImage:[UIImage imageNamed:#"line.png"]];
lineView.backgroundColor = patternColor;
[self.view addSubview:lineView];

If this is a label you will be using a lot, you could make a sub-class of UILabel and override the drawRect function.
- (void) drawRect:(CGRect)r
{
[super drawRect:r];
CGContextRef context = UIGraphicsGetCurrentContext();
CGContextSaveGState(context);
CGContextSetStrokeColorWithColor(context, [UIColor redColor].CGColor);
CGContextSetLineWidth(context, 1.0);
CGContextMoveToPoint(context, 1.0, 1.0);
CGContextAddLineToPoint(context, self.bounds.size.width - 1.0, 1.0);
CGContextStrokePath(context);
CGContextRestoreGState(context);
}
The advantage here is that the line will be "baked" into the view and only be draw once. Other methods such as CAShapeLayer or UIView will be re-rendered every frame.
For bonus points, you can make the color and line width properties :)

Related

Round specific corners of and show shadow on specific sides only

I have the following piece of code to round only specific corners of a view:
- (void)roundOnlySpecifiedCornersInView:(UIView *)view corners:(UIRectCorner)corners
{
UIBezierPath *maskPath = [UIBezierPath bezierPathWithRoundedRect:view.bounds byRoundingCorners:(corners) cornerRadii:CGSizeMake(4.0, 4.0)];
CAShapeLayer *maskLayer = [[CAShapeLayer alloc] init];
maskLayer.path = maskPath.CGPath;
view.layer.mask = maskLayer;
}
This works perfectly in isolation. Now I also want shadow in my view, but I specifically want to apply shadow in different cases:
on all sides
all sides except bottom
all sides except top
left/right sides only
All techniques I encountered work by creating an inset of the view. The problem with this, is that, say you want to only keep shadow on left/right sides, you offset bottom and top. Since the Rect is now less high, the shadow at the left and right does not cover the full height of the view. Also, the mask layer used for rounding corners causes the shadow to no longer appear.
Example code for this:
innerView.layer.shadowColor = [[UIColor colorWithWhite:0.0f alpha:0.1f] CGColor];
innerView.layer.shadowOpacity = 1.0f;
innerView.layer.shadowOffset = CGSizeMake(0.0f, 0.0f);
innerView.layer.shadowRadius = 6.0f;
CGRect shadowFrame = UIEdgeInsetsInsetRect(innerView.bounds, UIEdgeInsetsMake(9, 0, 9, 0));
CGPathRef shadowPath = [UIBezierPath bezierPathWithRect:shadowFrame].CGPath;
innerView.layer.shadowPath = shadowPath;
How can I round specific corners in a view and at the same time show shadow only at specified sides?
Answers in Swift are appreciated too!
Screenshot of what I want (this one is easy since all corners need to be rounded so I can use .layer.cornerRadius and it has shadow at all sides):
Now I just want to round only 2 of the corners (top left and top right, bottom left and bottom right) and add shadow to only some sides.
I'm not sure if it meet your demand. The code create an image with top and bottom shadow, and all rounding corner, you can modify the code to achieve what you need. You can use the image as the background of your cell(It's seems that it is UITableViewCell)
Let me know if it don't work for you.
The image:
// create a shadow image
CGSize size = CGSizeMake(ScreenWidth, ScreenWidth);
UIGraphicsBeginImageContextWithOptions(size, NO, 0);
CGContextRef context = UIGraphicsGetCurrentContext();
UIColor *backgroundColor = [UIColor colorWithRed:246.0/255.0 green:246.0/255.0 blue:246.0/255.0 alpha:1.0];
UIColor *fillColor = [UIColor whiteColor];
CGRect rect = CGRectMake(10, 10, 100, 44);
// re-draw the background
CGContextSetFillColorWithColor(context, backgroundColor.CGColor);
CGContextFillRect(context, CGRectMake(0, 0, size.width, size.height));
// set top and bottom shadow
CGRect rectTop = CGRectMake(rect.origin.x, rect.origin.y, rect.size.width, 5);
CGContextSaveGState(context);
CGContextSetShadowWithColor(context, CGSizeMake(0, -5), 5, [UIColor colorWithRed:0 green:0 blue:0 alpha:0.1].CGColor);
CGContextSetFillColorWithColor(context, [UIColor redColor].CGColor);
CGContextFillRect(context, rectTop);
CGContextRestoreGState(context);
CGRect rectBottom = CGRectMake(rect.origin.x, rect.origin.y+rect.size.height-5, rect.size.width, 5);
CGContextSaveGState(context);
CGContextSetShadowWithColor(context, CGSizeMake(0, 5), 5, [UIColor colorWithRed:0 green:0 blue:0 alpha:0.1].CGColor);
CGContextSetFillColorWithColor(context, [UIColor redColor].CGColor);
CGContextFillRect(context, rectBottom);
CGContextRestoreGState(context);
// re-draw the background
CGContextSetFillColorWithColor(context, backgroundColor.CGColor);
CGContextFillRect(context, rect);
CGContextSaveGState(context);
UIBezierPath *maskPath = [UIBezierPath bezierPathWithRoundedRect:rect byRoundingCorners:UIRectCornerAllCorners cornerRadii:CGSizeMake(4.0, 4.0)];
[maskPath addClip];
CGContextSetFillColorWithColor(context, fillColor.CGColor);
CGContextFillRect(context, rect);
CGContextRestoreGState(context);
You can modify the code to get a top left shadow:
// create a shadow image
CGSize size = CGSizeMake(ScreenWidth, ScreenWidth);
UIGraphicsBeginImageContextWithOptions(size, NO, 0);
CGContextRef context = UIGraphicsGetCurrentContext();
UIColor *backgroundColor = [UIColor colorWithRed:246.0/255.0 green:246.0/255.0 blue:246.0/255.0 alpha:1.0];
UIColor *fillColor = [UIColor whiteColor];
CGRect rect = CGRectMake(10, 10, 100, 44);
// re-draw the background
CGContextSetFillColorWithColor(context, backgroundColor.CGColor);
CGContextFillRect(context, CGRectMake(0, 0, size.width, size.height));
// set top and left shadow
CGRect rectTop = CGRectMake(rect.origin.x, rect.origin.y, rect.size.width, 5);
CGContextSaveGState(context);
CGContextSetShadowWithColor(context, CGSizeMake(0, -5), 5, [UIColor colorWithRed:0 green:0 blue:0 alpha:0.1].CGColor);
CGContextSetFillColorWithColor(context, [UIColor redColor].CGColor);
CGContextFillRect(context, rectTop);
CGContextRestoreGState(context);
CGRect rectLeft = CGRectMake(rect.origin.x, rect.origin.y, 5, rect.size.height);
CGContextSaveGState(context);
CGContextSetShadowWithColor(context, CGSizeMake(-5, 0), 5, [UIColor colorWithRed:0 green:0 blue:0 alpha:0.1].CGColor);
CGContextSetFillColorWithColor(context, [UIColor redColor].CGColor);
CGContextFillRect(context, rectLeft);
CGContextRestoreGState(context);
// re-draw the background
CGContextSetFillColorWithColor(context, backgroundColor.CGColor);
CGContextFillRect(context, rect);
CGContextSaveGState(context);
UIBezierPath *maskPath = [UIBezierPath bezierPathWithRoundedRect:rect byRoundingCorners:UIRectCornerAllCorners cornerRadii:CGSizeMake(4.0, 4.0)];
[maskPath addClip];
CGContextSetFillColorWithColor(context, fillColor.CGColor);
CGContextFillRect(context, rect);
CGContextRestoreGState(context);
HTH
In many, many cases you would want to achieve this with drawing the shadow, of course. However, you may consider the following approach: using a stretchable image with the shadow just on the sides that you need, e.g. something similar to (this one has shadow on all sides though):
Just before you say: "Ewwwww! He's using an image for a simple shadow!" let me emphasise that this will work much better in terms of performance. For instance, if you have a lot of cells in a UICollectionView and each one is re-drawing its shadow it could significantly slow down your app during scrolling, whereas with an image-based shadow it's going to be essentially the same.
I would go even further and suggest that you could actually use a stretchable image for masking the view with rounded corners, too! Now, this may look like going a bit too far, but if you notice a drastic decrease in performance I would give it a shot. What you essentially need to do is prepare another stretchable image with a transparent "middle" part and rounded corners of the same colour as your background. Something like:
And again, before you downvote this bizarre way of doing something that can be easily achieved with two lines of code...
view.layer.cornerRadius = 20
view.layer.masksToBounds = true
...Let me point out that this will work ridiculously faster in cases when you have to display a bunch of those masked views simultaneously: for instance, masking UICollectionViewCells. Basically, if you set a mask on a UIView's layer, this mask is going to be re-calculated and applied in real time, which would cost you a lot in terms of performance during frequent redrawing of the UIView contents — when scrolling a UITableView or UICollectionView, for example.
Obviously this wouldn't work if your background is not of a solid colour, and has a gradient for instance. However, in many other cases this may help you achieve much smoother UI performance. Another advantage in your particular case is that you can easily control which corners to mask and where the shadow should drop.
Again, I'm not implying that this is the way to go in each and every case. What I'm saying is that there are a lot of cases when this could help increase the performance significantly: for example, if you are masking far too many views that are rendered on the screen at the same time, and the layout is expected to be redrawn frequently.
for specific corner set corner radius
refer from : how to set cornerRadius for only top-left and top-right corner of a UIView?
UIBezierPath *maskPath;
maskPath = [UIBezierPathbezierPathWithRoundedRect:_backgroundImageView.bounds
byRoundingCorners:(UIRectCornerBottomLeft|UIRectCornerBottomRight)
cornerRadii:CGSizeMake(3.0, 3.0)];
CAShapeLayer *maskLayer = [[CAShapeLayer alloc] init];
maskLayer.frame = self.bounds;
maskLayer.path = maskPath.CGPath;
_imageView.layer.mask = maskLayer;
[maskLayer release];

UIImageView sides and top rounded borders

Hi all I need to realize borders around an UIImageView like these.
Left, top and right border like an half-moon
http://imageshack.com/a/img841/3269/o90p.png
How can i do it ?
You can user CALayer for the same.
CALayer *l = [_btn layer];
[l setMasksToBounds:YES];
[l setCornerRadius:8.0];
and add QuartzCore.framework
You may want to subclass UIView and override the drawRect: method. Then place add your image view as a subview. Your drawRect: method would look something like this (with clipsToBounds set to YES):
- (void)drawRect:(CGRect)rect
{
UIColor *fillColor = [UIColor clearColor];
UIColor *borderColor = [UIColor redColor];
float borderWidth = 2.0f;
CGContextRef context = UIGraphicsGetCurrentContext();
CGContextSetFillColorWithColor(context, fillColor.CGColor);
CGContextSetLineWidth(context, borderWidth);
CGContextSetStrokeColorWithColor(context, borderColor.CGColor);
CGContextMoveToPoint(context, CGRectGetMinX(rect), CGRectGetMidY(rect));
CGContextAddArc(context, CGRectGetMidX(rect), CGRectGetMidY(rect), rect.size.height/2, 2*M_PI, M_PI, 1);
CGContextClosePath(context);
CGContextDrawPath(context, kCGPathFillStroke);
}
Alternatively you can look into masking with a semicircle image or creating a CAShapeLayer for the image view.
You need to:
Create a CAShapeLayer
Set its path to be a CGPathRef based on view.bounds but with only two rounded corners (probably by using [UIBezierPath
bezierPathWithRoundedRect:byRoundingCorners:cornerRadii:])
Set your view.layer.mask to be the CAShapeLayer
Just take in account that this have a bad effect on performance. This might help

iOS make hole in UIView other shape than square

I have a UIView that draws different shapes. I can make a hole in my image to have it transparent, working fine, but the hole is only square,
//hole
CGRect holeRectValue = CGRectMake(300, 40, 80, 100);
CGRect holeRectIntersection = CGRectIntersection( holeRectValue, rect );
[[UIColor clearColor] setFill];
UIRectFill(holeRectIntersection);
Now I need to make the hole in the image but not as a rect, as the shape of my drawn figure,
Here is the code:
- (id)initWithFrame:(CGRect)frame forNode0:(CGPoint)node0 forNode1:(CGPoint)node1 fornode2:(CGPoint)node2 fornode3:(CGPoint)node3 fornode4:(CGPoint)node4 fornode5:(CGPoint)node5 fornode6:(CGPoint)node6 fornode7:(CGPoint)node7 fornode8:(CGPoint)node8 fornode9:(CGPoint)node9
{
self = [super initWithFrame:frame];
if (self) {
self.opaque = NO;
self.node0Pos = node0;
self.node1Pos = node1;
self.node2Pos = node2;
self.node3Pos = node3;
self.node4Pos = node4;
self.node5Pos = node5;
}
return self;
}
// Only override drawRect: if you perform custom drawing.
// An empty implementation adversely affects performance during animation.
- (void)drawRect:(CGRect)rect
{
//bgnd
UIGraphicsBeginImageContext(self.frame.size);
[[UIImage imageNamed:#"cat.jpeg"] drawInRect:self.bounds];
UIImage *image = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
[[UIColor colorWithPatternImage:image] setFill];
// Drawing code
UIRectFill(rect);
// Drawing code
//1. begin new path
CGContextRef context = UIGraphicsGetCurrentContext();
CGContextBeginPath(context);
//2. move to initial starting point
CGContextMoveToPoint(context, self.node0Pos.x, self.node0Pos.y);
//3. add lines defining shape
CGContextAddLineToPoint(context, self.node1Pos.x, self.node1Pos.y);
CGContextAddLineToPoint(context, self.node2Pos.x, self.node2Pos.y);
CGContextAddLineToPoint(context, self.node3Pos.x, self.node3Pos.y);
CGContextAddLineToPoint(context, self.node4Pos.x, self.node4Pos.y);
CGContextAddLineToPoint(context, self.node5Pos.x, self.node5Pos.y);
//4. optionally close path
CGContextClosePath(context);
CGColorRef color;
//5. draw path
color = [UIColor colorWithRed:1 green:0 blue:228/255.0f alpha:0.5].CGColor;
//CGContextSetFillColor(context, color);
CGContextSetFillColorWithColor(context, color);
CGContextDrawPath(context, kCGPathFill);
//
//hole
CGRect holeRectValue = CGRectMake(300, 40, 80, 100);
CGRect holeRectIntersection = CGRectIntersection( holeRectValue, rect );
[[UIColor clearColor] setFill];
UIRectFill(holeRectIntersection);
}
So how do I make the "hole" with my actual context path?
P.S. I was doing some masking, but it leaves a white line around the hole, so I need to avoid this.
[[UIColor clearColor] setFill];
UIRectFill(holeRectIntersection);
This doesn’t do anything—drawing with a clear color is effectively a no-op. What you most likely want to do is add the rectangle you’re trying to cut out as part of the path you’re creating, i.e. inserting a call to CGContextAddRect before your CGContextClosePath. See Filling a Path in the Quartz 2D Programming Guide.
I believe what you're looking for is the CALayer.mask property. To create a "hole", you would generate a CALayer object with an alpha channel in the shape of the hole you want to make, and then apply it to the view you want to punch the hole in.
In semi-pseudocode:
CALayer *holeMask;
UIView *myView;
//
// Build the holeMask object via whatever means,
// and set myView to the target view that you want
// to punch the hole in...
//
myView.layer.mask = holeMask

ios how to make a camera circle mask

everybody,
I want to make the circle mask on the camera.
i try this way:
- (void)drawRect:(CGRect)rect
{
// Drawing code
CGContextRef context = UIGraphicsGetCurrentContext();
CGContextAddArc(context, self.frame.size.width/2, self.frame.size.height/2, 200, 0, M_PI *2, 0);
//Set the stroke color to black
[[UIColor blackColor]setStroke];
//Define line width and cap
CGContextSetLineWidth(context, 200);
CGContextSetLineCap(context, kCGLineCapButt);
//draw it!
CGContextDrawPath(context, kCGPathStroke);
}
just set the line with enough big,but i think it can set alpha.
thanks.
[[UIColor colorWithRed:0 green:0 blue:0 alpha:alpha/255.0] setStroke];
set the alpha percent you want
As you don't mentioned adjustable circle mask, I assume you need a static circle mask over on the camera view. If you need dynamically created circle, this is not the right answer.
Anyway it might help to know a simple way to do this:
prepare a png which is a circle actually, and the inside of that circle is transparent (make sure you handle the proper width and height or even create multiple circle pngs for different devices eg. iPhone5 and iPhone4)
use the imagePickerController's cameraOverlayView property to add the overlay image
UIView *tmp_camera_overlay = [[UIView alloc] initWithFrame:CGRectMake(0, 0, 320, 480)];
UIImageView *tmp_camera_bkgr =[[UIImageView alloc] initWithImage:[UIImage imageNamed:#"circle_screen_overlay.png"]];
tmp_camera_bkgr.frame = CGRectMake(0, 0, 320, 480);
[tmp_camera_overlay addSubview:tmp_camera_bkgr];
imagePickerController.cameraOverlayView = tmp_camera_overlay;

How to remove border from some part of UIView?

I am having a UIView which contains other subviews. I am applying border to this UIView and the border is applied to the whole UIView. For that see the first image.
But do not want the border around the title where it says "Leaderboard". How can i remove the border for that portion only. See the below image and in that see that there is no border around the header Leaderboard..
NO,CALayer borders don’t support that behavior.
But you can try an alternate method if you need to implement this,
try adding an n-point-wide opaque subview with your desired border color as its background color, on each side of your main view.
Add this Code:
CGSize mainViewSize = theView.bounds.size;
CGFloat borderWidth = 2;
UIColor *borderColor = [UIColor redColor];
CGFloat heightfromTop = 25;
UIView *leftView = [[UIView alloc] initWithFrame:CGRectMake(0, heightfromTop borderWidth, mainViewSize.height-heightfromTop)];
UIView *rightView = [[UIView alloc] initWithFrame:CGRectMake(mainViewSize.width - borderWidth, heightfromTop, borderWidth, mainViewSize.height-heightfromTop)];
leftView.opaque = YES;
rightView.opaque = YES;
leftView.backgroundColor = borderColor;
rightView.backgroundColor = borderColor;
[mainView addSubview:leftView];
[mainView addSubview:rightView];
This will add borders to both sides only.Repeat the same idea for top and bottom also.
NB : heightfromTop is the height of the top section where you don't want the border view to be present, you can alter it as per your needs
You can subclass the UIView and implement the drawRect like:
- (void)drawRect:(CGRect)rect
{
float borderSize = 3.0f;
//draw the bottom border
CGContextSetFillColorWithColor(context, [UIColor blueColor].CGColor);
CGContextFillRect(context, CGRectMake(0.0f, self.frame.size.height - borderSize, self.frame.size.width, borderSize));
//draw the right border
CGContextSetFillColorWithColor(context, [UIColor blueColor].CGColor);
CGContextFillRect(context, CGRectMake(0.0f,0.0f, borderSize,self.frame.size.height));
//draw the left border
CGContextSetFillColorWithColor(context, [UIColor blueColor].CGColor);
CGContextFillRect(context, CGRectMake(self.frame.size.width - borderSize,0.0f, borderSize,self.frame.size.height));
}
Now, you need to use the subclassed UIView for creating the needed view.

Resources