I'm trying to add some shadow under a UIView.
In drawRect I created a rounded rectangle bezier path and appended a curved arrow-like bottom part to it (blue stuff)
Here is the shadow's code :
...
CGContextSaveGState(context);
CGContextAddPath(context, rectPath.CGPath); // rectPath is the bezier
CGContextSetShadowWithColor(context,shadowSize, 3.0, [[[UIColor blackColor] colorWithAlphaComponent:0.7]CGColor]);
CGContextFillPath(context);
CGContextRestoreGState(context);
...
As you can see, the shadow is cut off at the bottom, that's where the view's frame ends. Can I extend the shadow "outside" the frame ?
use the CALayer shadow properties instead of drawing the shadow in drawRect:
shadowOpacity
shadowRadius
shadowOffset
shadowColor
shadowPath
this can result in some performance issues, which you can reduce by using the shadowPath property.
Related
I want to add a drop shadow effect underneath my UIImageView instances, like in the screenshot below:
How can I achieve this, either through storyboards or code (Objective-C)?
//Drop Shadow
[view.layer setShadowColor: [UIColor grayColor].CGColor];
[view.layer setShadowOpacity:0.8];
[view.layer setShadowRadius:3.0];
[view.layer setShadowOffset:CGSizeMake(2.0, 2.0)];
Please Try this once :-
UIBezierPath *shadowPath = [UIBezierPath bezierPathWithRect:view.bounds];
view.layer.masksToBounds = NO;
view.layer.shadowColor = [UIColor blackColor].CGColor;
view.layer.shadowOffset = CGSizeMake(0.0f, 5.0f);
view.layer.shadowOpacity = 0.5f;
view.layer.shadowPath = shadowPath.CGPath;
Explanation :-
As seen in the last step there are a few different properties needed when adding a shadow using Core Animation. If your are not familiar with Core Animation don’t worry, just try to focus on the shadow code and not the CALayer on the view.
shadowOffset is a CGSize representing how far to offset the shadow from the path.
shadowColor is the color of the shadow. Shadow colors should always be opaque, because the opacity will be set by the shadowOpacity property. The shadowColor property is a CGColor not a UIColor.
shadowRadius is the width of the shadow along the shadow path
shadowOpacity determines the opacity of the shadow.
shadowPath is probably the most important of the properties. While a shadow can be drawn without specifying a path, for performance reasons you should always specify one. This path tells Core Animation what the opaque regions of the view are, and without it, things slow down severely! It is a CGPath, which is most easily created using UIBezierPath (iOS only) as shown in step 2.
See more in http://nscookbook.com/2013/01/ios-programming-recipe-10-adding-a-shadow-to-uiview/
Those are not lights, but shadow. You can use the layer to draw shadow for UI elements.
I am drawing a circle in my custom UIView's drawRect:
- (void)drawRect:(CGRect)rect {
...
UIBezierPath *ovalPath = [UIBezierPath bezierPathWithOvalInRect:rect];
[UIColor.whiteColor setStroke];
ovalPath.lineWidth = 1;
[ovalPath stroke];
}
The oval is always clipped on the edge. How can I avoid the clipping? Is insetting the rect the only way?
CG draws the stroke centered on the path -- half inside the path, half outside the path. Therefore, part of the stroke is outside of your view, and you don't see it.
Inset the rect by half the stroke width.
CGRect rectToStroke = CGRectInset(rect, 0.5, 0.5);
UIBezierPath *ovalPath = [UIBezierPath bezierPathWithOvalInRect: rectToStroke];
Anything you draw inside of -drawRect: using CG or UIKit goes into a bitmap context which is the size of your view's bounds.
If you need to show something bigger than bounds.size, you have two options: make the view's bounds bigger, or draw via some other method, such as:
add a subview which is bigger (but it will appear on top of your view, so you'll need to make it partially transparent)
add a CALayer or CAShapeLayer to your view's layer (with the same caveat)
set your view's layer's borderWidth to draw a border on top of the contents
(For all of these, you may find that you also need to set your view's clipsToBounds property to NO, if it isn't already.)
I'm overriding -drawRect: to draw some custom views. Usually, I'm drawing a filled rounded rect bezier path with a drop shadow. However, I've run into an annoying issue: when I set the shadow color, the fill color is also changed to the same color!
Is this a bug in Core Graphics or am I missing something here? Here's an example of my code where I'm trying to draw a path with a shadow. translucentBlack and highlight are two different UIColor objects, but what gets drawn is a rounded rect that is filled with the highlight color as well as the shadow in the highlight color.
UIBezierPath* blackTranslucentRoundedRectPath = [UIBezierPath bezierPathWithRoundedRect: CGRectMake(CGRectGetMinX(frame) + 5, CGRectGetMinY(frame) + 5, CGRectGetWidth(frame) - 10, CGRectGetHeight(frame) - 10) cornerRadius: 8];
CGContextSetShadowWithColor(context, highlightOffset, highlightBlurRadius, highlight.CGColor);
[translucentBlack setFill];
[blackTranslucentRoundedRectPath fill];
Any ideas? Thanks!
What's happening is that you can see your highlight color through your translucent black color. Change the translucentBlack to any non-transparent color (make its alpha equal 1.0) and you should be fine.
i'm struggling creating a drop shadow around a CALayer. For the effect i'm trying to achieve i need to have access to the "intensity" of the shadow. Somehow like the "spread" slider in Photoshop's Layer Styles. I think the "ShadowRadius" property of CALayer is equivalent to Photoshop's "Size" slider.
Any suggestions? Is maybe a radial gradient an option?
Set the layer's shadowOffset,shadowOpacity, and shadowRadius and you should have what you are looking for. Try this for a shadow project directly "underneath" the layer with a blur of 5 pixels, which with the right color, could also make it look like a glow:
CALayer *layer = myView.layer;
layer.shadowOpacity = 0.50;
layer.shadowRadius = 5.0;
layer.shadowOffset = (CGSize){.width=0.0,.height=0.0};
You can control "spread" by setting custom shadowPath property on a CALayer.
CGFloat radius = CGRectGetWidth(view.bounds)/2.0;
// this is a sample code for a circle, but you can use any shape you want
CGPathRef shadowPathRef = [UIBezierPath bezierPathWithRoundedRect:CGRectMake(0, 0, 2.0 * radius, 2.0 * radius) cornerRadius:radius].CGPath;
layer.shadowPath = shadowPathRef;
If you set radius to a bigger value, shadow spread will be bigger.
I'm trying to draw a custom button frame as follows:
UIBezierPath *stroke = [UIBezierPath bezierPathWithRoundedRect:self.bounds
cornerRadius:RECT_CORNECR_RADIUS];
[stroke stroke];
But for some reason the corner curves look thinker than the sides. If you look at the UIButton's default frame it's very uniform. A is a UIButton, B is a custom button.
Any ideas how I can make it more like the UIButton.
You are stroking the bounds of your button. This will draw your line centred over the edge the view, so half of the thickness of the line is outside the bounds and is not drawn. This is why it is full thickness in the corners. Use CGRectInset on your bounds rectangle (inset by half the thickness of your line) and stroke THAT rect.
The problem you have is probably due to antialiasing. You can try to change the antialiasing settings of CoreGraphics before drawing your beizerPath.
An easier solution is to use the CALayer of your button and its cornerRadius property. It would be easier to draw a rounded corner
If self is your custom button:
self.layer.cornerRadius = RECT_CORNER_RADIUS;
self.layer.borderWidth = 1.0f;
self.layer.borderColor = [UIColor blackColor].CGColor;
Of course don't forget to import the QuartzCore framework and import its header for this to work (#import )