I am trying to add shadow to an UIImage that is inside a UITableViewCell. I configured image using UIBezierPath to draw a shadow around its bounds. The shadow appear on either side of the image but the shadow on the top of image is clipped by the table view cell's border because there is no space between image's top and the table cell's border. I cannot have space between image's top and border because these cells are collapsible and will clip lower parts of the image to make it look like a carousel of cards stacked one on the top of another. Here is the code I am using to generate shadows:
let shadowPath = UIBezierPath(rect: self.bounds)
layer.masksToBounds = false
self.clipsToBounds = false
layer.shadowColor = UIColor.blackColor().CGColor
layer.shadowOffset = CGSizeMake(0.0, -3.0)
layer.shadowOpacity = 0.1
layer.shadowRadius = 0.56
layer.shadowPath = shadowPath.CGPath
Here is a screenshot of what I'm trying to achieve:
What I've done so far is dynamically load table cells with images of cards, hide overflow of image that are greater than the height of the cells, increase height of cells on tap so that the tapped card pushes other cards below it by increasing the height of the cell and come to full view mode.
The problem is the shadows on top of the card gets hidden because maybe it tresspasses into the cell above it?
I understand that my entire approach might be wrong on this one, so I'm open to any suggestions. Please help.
UPDATE
https://github.com/gleue/TGLStackedViewController -> TGLStackedViewController
This view controller is exactly what I want plus shadows on top. Now I've come to realize that I do not need to render shadows while viewing but adding shadows while saving image will do. It is more efficient as well because the app does not have to draw the shadows every time the image is being displayed The problem however, is, this library is written in ObjC and is compatible with iOS9+ only.
Related
Multiple placed in my app, I have views with both shadows and corner radii. I tried adding a new view, and suddenly the code I was reusing doesn't work anymore. I can only set a corner radius or a shadow, depending on what I put for masksToBounds. Here's the code I use for both the faulty view and my other views:
itemCountLabel.layer.masksToBounds = false
itemCountLabel.layer.cornerRadius = itemCountLabelSize / 2.0
itemCountLabel.layer.shadowColor = UIColor.black.cgColor
itemCountLabel.layer.shadowOpacity = 0.25
itemCountLabel.layer.shadowRadius = 5
itemCountLabel.layer.shadowOffset = CGSize(width: 4, height: 4)
contentView.addSubview(itemCountLabel)
It's not possible to implement as you've tried. Shadow is always applied outside the bounds of the UIView and the cornerRadius will not be visible without masking the bounds of UIView. So, better add a UIView behind the UILabel and to reuse the function write an extension of UIView that returns a UIView contains the view you want to apply the shadow.
Here you need to use two different views one to round the corners and the other behind it to show the shadow, As both these properties don’t work together because of the Mask To Bounds and Clip To Bounds features. As corner radius needs to clip the edges which might can contain the shadow.
So to have both of the things use a shadow view behind the view which you want to have rounded corners.
I have a collection view with rounded and shadow-dropped cells. The shadow of the cell suddenly disappears, instead of smoothly moving out of the view, when the cell is about to be covered by the navigation bar. Below is the code:
contentView.layer.cornerRadius = 20
contentView.layer.masksToBounds = true
layer.shadowColor = UIColor.black.cgColor
layer.shadowOpacity = 0.1
layer.shadowOffset = CGSize(width: 0, height: 5.0)
layer.shadowRadius = 5.0
layer.shadowPath = UIBezierPath(roundedRect: bounds, cornerRadius: contentView.layer.cornerRadius - 3).cgPath
layer.shouldRasterize = true
layer.rasterizationScale = UIScreen.main.scale
Here is the gif showing the problem. Focus on the shadow at the bottom of the cell. The navigation bar is white. Any help would be appreciated. Thank you!
Instead of setting shadow of contentView embed all your content in a UIView and set shadow of that view instead. Then you have to increase the height of your cell about 20 points or as much your shadow height. That should work I guess.
I believe it's simply because the cell does really get removed from the view, thus it's shadow goes with it. At that point the frame of the cell is out of the view, while shadow is still visible (shadow is around the frame) - but when the frame goes out of view, the collectionView removes the cell. And so the shadow disappears abruptly.
What I would do about it is very simple. I would refactor the code to wrap the current cell contents into a new UIView - lets call it wrapper, that will drop the shadow. Then put this wrapper into the cell's contentView so that the wrapper along with its shadow will fit inside of the contentView. Then the shadow will become a part of the contentView frame, which means that the shadow will disappear from the screen only when the whole cell is hidden.
Of course, you will have to modify the collectionView's size for cell, because now the cells will be bigger to contain also the shadow.
This question already has an answer here:
iOS clipsToBounds YES and Shadow?
(1 answer)
Closed 5 years ago.
I need to design a view like card with rounded corner and shadow. I have one container view and inside that another view as like image I have attached. But when I am applying corner radius for the outer container view radius is getting set except the area which is having inner view. If I am making it clipToBounds = true then it is getting round all over but shadow is not coming. So plz help me out here.
Here is my code
containerView.layer.masksToBounds = false
containerView.layer.shadowColor = UIColor.black.cgColor
containerView.layer.shadowOpacity = 0.5
containerView.layer.shadowOffset = CGSize(width: -1, height: 1)
containerView.layer.shadowRadius = 5
containerView.backgroundColor = UIColor.white
containerView.layer.cornerRadius = 20
I am attaching Image below for for my issue. View Image
You have two views, a superview and its subview, and your goals are in conflict.
On the one hand, you want the corner radius of the superview to affect its subview. That can happen only if the superview masks to its bounds.
On the other hand, you want the superview's shadow to appear. That can happen only if the superview doesn't mask to its bounds.
So what you want is a logical impossibility.
The solution is easy. Use three views! Divide the job of shadow-making and clipping between two views.
The outermost view has the corner radius and the shadow and doesn't mask to bounds. This is the shadow-maker.
The next view is its subview. It is exactly the same size, and it also has the corner radius and it does mask to bounds. This is the clipper.
The next view is the content, the subview(s) of the subview. It will be masked by the second view so the corner radius will affect it.
I'm trying to set a dropshadow on a UITableView which is being added programmatically.
The frame height is being set to a certain percentage of the screen. So I want to set a dropshadow on the tableview itself.
I tried doing the following:
tableview_results.layer.shadowPath = UIBezierPath(rect: tableview_results.frame).cgPath
tableview_results.layer.shadowColor = UIColor.black.cgColor
tableview_results.layer.opacity = 1
tableview_results.layer.shadowOffset = CGSize.zero
tableview_results.layer.shadowRadius = 10
However this doesn't seem to do anything.
When I try searching for a solution, I only find stuff regarding how to set a dropshadow on the last cell of the UITableView. However this would not work for me since then the shadow will only be displayed when the last cell is displayed.
I need the shadow to be always present on the UITableView.
The shadow path should be set to the tableview_results.bounds not frame. The bounds is the rectangle around the table view in the coordinate system of the table view itself, and that's the correct coordinate system in which to specify the shadow path. Alternatively, you can just not set the shadow path at all and the shadow will draw in the correct place (though perhaps there's a performance benefit to setting the path explicitly if you can do so reliably).
You also need to set the shadowOpacity not the opacity of the layer, to 1. And you need to tell the tableview_results to not clipToBounds. So something like this:
tableview_results.layer.shadowPath = UIBezierPath(rect: tableview_results.bounds).cgPath
tableview_results.layer.shadowColor = UIColor.black.cgColor
tableview_results.layer.shadowOpacity = 1
tableview_results.layer.shadowOffset = CGSize.zero
tableview_results.layer.shadowRadius = 10
tableview_results.clipsToBounds = NO;
And for that last line, if you feel like the code is cleaner by only talking to the layer, you can equivalently use tableview_results.layer.masksToBounds = NO.
Note that there is a side effect of turning off clipping: Now you might see table view cells beyond the bounds of the table view itself! So there might be better ways to get the shadow effect. You could, for example, wrap the table view in a simple superview that tightly bounds the tableview, and give the shadow to that superview. Just a thought.
How would I change my cells in the UITableViewCells to have rounded corners? Kind of like this:
I like the gaps that are present, so is there away to adjust that as well?
In the ContentView of the UITableViewCell you can set, this lines the get the rounded corner.
self.layer.cornerRadius = 5.0
self.clipsToBounds = true
self.layer.masksToBounds = true
To give the gap, you need to set the default content view to Clear Color (to be transparent), and add a View inside the cell, with a smaller size then the cell.
It will look like this in the storyboard.