Draw Shadow Only *Around* UIView Which Contains Transparency - ios

Question I'm struggling on. I've searched SO for a fair good time by now, but couldn't find an answer.
I have a UIView which contains alpha value of 0.5, means - it transparent.
If I'm applying the usual code for UIView shadowing -
class func applyShadow(view : UIView)
{
view.layer.shadowColor = UIColor.blackColor().colorWithAlphaComponent(0.15).CGColor
view.layer.shadowOpacity = 1
view.layer.shadowOffset = CGSizeMake(0, 0.5)
view.layer.shadowRadius = 1.3
view.layer.masksToBounds = false
view.layer.shouldRasterize = true
view.layer.rasterizationScale = UIScreen.mainScreen().scale
}
The "fill" of the my UIView get shadowed as well.
How can I draw the shadow only on the "border" path of my UIView, excluding the UIView fill?

For 2022 this is now possible.
Essentially you do this:
shadowHole.fillRule = .evenOdd
shadowHole.path = p.cgPath
full details ...
https://stackoverflow.com/a/59092828/294884

Related

UIKit: How to mix several CALayers into one view layer?

I would like to mix several sublayers into only one layer.
If I simply assign my modifications to the view layer, it works fine:
testView.layer.cornerRadius = 15.0
testView.layer.shadowColor = UIColor.yellow.withAlphaComponent(1.0).cgColor
testView.layer.shadowOpacity = 1.0
testView.layer.shadowRadius = 24.0
testView.layer.shadowOffset = .zero
testView.backgroundColor = .white
Then, I tried this:
testView.layer.cornerRadius = 15.0
// sl1
let layer1 = CALayer()
layer1.shadowColor = UIColor.yellow.withAlphaComponent(1.0).cgColor
layer1.shadowOpacity = 1.0
layer1.shadowRadius = 24.0
layer1.shadowOffset = .zero
// sl2
let layer2 = CALayer()
layer2.shadowColor = UIColor.red.withAlphaComponent(1.0).cgColor
layer2.shadowOpacity = 1.0
layer2.shadowRadius = 24.0
layer2.shadowOffset = .zero
// sublayers
let layer = CALayer()
testView.layer.sublayers = [layer1, layer2]
testView.backgroundColor = .white
But now here is the result I get
There is now no shadow surrounding the white view. Why is this happening?
Thank you for your help
The chief problem with your code is that none of your layers have any size. Thus for example you see no shadow, because the layer itself is of zero size in the top left corner so there is nothing there to cast any shadow.
It is your job to give a layer a frame immediately after creating it! Typically this will be the same as the bounds of the superlayer. Keep in mind, however, that unlike views, when a view or superlayer is resized, sublayers are not. Thus the sublayer can cease to "fit" its superlayer properly if you don't take measures to correct that.

IOS - When I rotate a UIView the edges become distorted

I tried rotating a UIView using:
view.transform = CGAffineTransform.init(rotationAngle: 45)
only to see the edges of the view looked very distorted.
Is this normal? And if it is, are there any workarounds to straighten the edges?
EDIT
I found that adding the piece of code below works the best
view.layer.allowsEdgeAntialiasing = true
refer this link,
https://stackoverflow.com/a/8313978/6742121,
After that implement this for swift 3.0,
view.layer.borderWidth = 3
view.layer.borderColor = UIColor.clear.cgColor
view.layer.shouldRasterize = true
view.layer.rasterizationScale = UIScreen.main.scale()

Shadows slow up UIScrollView

I have a UIScrollView that pretty much functions like a Facebook news feed. I thought my elements were slowing the scroll fps down. By process of elimination, I found out that the shadows slow down my app.
The UIView boxes inside the scroll view have such configuration:
self.layer.shadowColor = UIColor.blackColor().CGColor
self.layer.shadowOffset = CGSizeMake(0, 2)
self.layer.shadowRadius = 2
self.layer.shadowOpacity = 0.15
Like a news feed, my scroll view has many boxes, therefore having UIViews with their own shadows. How do I go with this without slowing down my app?
There's a bunch of stuff on speeding up UIScrollViews:
CALayer - Shadow causes a performance hit?
https://markpospesel.wordpress.com/2012/04/03/on-the-importance-of-setting-shadowpath/
If you use custom CALayer instances -- especially with shadows -- stuff that requires processing power, you should use
scrollView.layer.shouldRasterize = YES;
scrollView.layer.rasterizationScale = [UIScreen mainScreen].scale;
Also a shadowPath could speed up your scrollview as well something like this:
[scrollView.layer setShadowPath:[[UIBezierPath bezierPathWithRect:myView.bounds] CGPath]];
Setting a shadowPath allows iOS to not recalculate how it should draw the shadow every time it draws the view, thus improving performance.
In swift, something like this:
let shadowPath = UIBezierPath(rect: view.bounds);
view.layer.masksToBounds = false;
view.layer.shadowColor = UIColor.blackColor().CGColor;
view.layer.shadowOffset = CGSizeMake(0, 0.5);
view.layer.shadowOpacity = 0.2;
view.layer.shadowPath = shadowPath.CGPath;
Setting the shadowPath will improve performance and look the same so long as your views are opaque. You could just set it to the bounds of the view or layer like so:
CGPathRef shadowPath = CGPathCreateWithRect(self.bounds, NULL);
self.layer.shadowPath = shadowPath;
CGPathRelease(shadowPath);
In Swift:
layer.shadowPath = CGPathCreateWithRect(bounds, nil)
The memory management is handled for you (discussed here).

Circular UIView (with cornerRadius) without Blended Layer

I'm trying to get the circle below to have an opaque solid white color where the cornerRadius cuts out the UIView.
UIView *circle = [[UIView alloc] initWithFrame:CGRectMake(i * (todaySize + rightMargin), 0, smallSize, smallSize)];
circle.layer.cornerRadius = smallSize/2;
circle.layer.borderWidth = 0.5;
circle.layer.backgroundColor = [UIColor whiteColor].CGColor;
circle.backgroundColor = [UIColor whiteColor];
[self addSubview:circle];
I've tried a few things like setting the backgroundColor and opaque without any luck. Color Blended Layers still shows that the surrounding of the circle is transparent. Does anybody know how to solve this?
To avoid blending when using rounded corners, the rounding needs to be done in drawRect, rather than as a property on the layer. I needed UICollectionView cells with a rounded background in an app I'm working on. When I used layer.cornerRadius, the performance took a huge hit. Turning on color blended layers yielded the following:
Not what I was hoping for, I want those cells to be colored green indicating there is no blending occurring. To do this, I subclassed UIView into RoundedCornerView. My implementation is real short and sweet:
import UIKit
class RoundedCornerView: UIView {
static let cornerRadius = 40.0 as CGFloat
override func drawRect(rect: CGRect) {
let borderPath = UIBezierPath(roundedRect: self.bounds, cornerRadius: RoundedCornerView.cornerRadius)
UIColor.whiteColor().set()
borderPath.fill()
}
}
Then I set the view I was rounding to be a RoundedCornerView in my nib. Running at that point yielded this:
Scrolling is buttery smooth and there is no longer any blending occurring. One odd side effect of this is that the view's backgroundColor property will color the excluded area of the corners, not the main body of the view. This means that the backgroundColor should be set to whatever is behind your view, not to the desired fill color.
Try using a mask to both avoid blending and dealing with the parent / child background color match.
override func layoutSubviews() {
super.layoutSubviews()
let maskLayer = CAShapeLayer()
maskLayer.path = UIBezierPath(roundedRect: bounds, cornerRadius: 20).cgPath
layer.mask = maskLayer
}
Set clipsToBoundson the view or masksToBounds on the layer to YES

Shadow in UIView without gradient ?

Does any one know how to achieve the shadow effect with no gradient? Like the screenshot show below
Another concern is the sequence of subviews, i.e the view in front may hide the effect of the view in behind. How to overcome this?
For the first problem you can change the shadowRadius of the shadow, for example:
//You must include QuartzCore framework (#import <QuartzCore/QuartzCore.h>)
view.layer.cornerRadius = 5;
view.layer.shadowRadius = 0; //The shadow should be rendered as a solid shape
view.layer.shadowOffset = CGSizeMake(0, 2);
view.layer.shadowOpacity = 0.5;
view.layer.shadowColor = [UIColor blackColor].CGColor;
UIBezierPath *path = [UIBezierPath bezierPathWithRect:view.bounds];
view.layer.shadowPath = path.CGPath; //This is very important!
Remember to always set the shadowPath! If you don't the performance of rendering the shadow will decrease a lot.
For the second problem, sorry but I don't think there's a way to let the shadow of an object appear over another view that is over the original one.

Resources