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.
Related
I am facing a strange issue when I try to apply rounded corners and shadow to my UITableView with dynamic content, which changes height as per the data (number of cells).
Here is screen recording of the jerky effect on scrolling.
My motive is to add shadow and corner radius to the dynamic table view.
When I add the corner radius it works fine, but when I try to add the shadow it doesn't show up. So I found a solution here saying that we need to set
self.tableView.clipsToBounds = false
self.tableView.layer.masksToBounds = false
However, after setting it I am getting the above jerky effect and the corner radius is no longer visible.
I tried other (proposed) solutions like adding a custom view on runtime with respect to tableview frame, but that creates a static height view and hence disabling the interactivity with the superview for that area.
Here is my code:
searchResultTblView.layer.cornerRadius = 10
searchResultTblView.layer.maskedCorners = [.layerMinXMaxYCorner , .layerMaxXMaxYCorner]
searchResultTblView.keyboardDismissMode = .onDrag
searchResultTblView.layer.shadowColor = UIColor.gray.cgColor
searchResultTblView.layer.shadowOpacity = 0.6
searchResultTblView.layer.shadowRadius = 5
searchResultTblView.tableFooterView = UIView.init(frame: CGRect.zero)
searchResultTblView.separatorInset = .zero
searchResultTblView.clipsToBounds = false
searchResultTblView.layer.masksToBounds = false
I know there's probably a better way to set both shadow and corner radius on the table view. However, I am currently unable to achieve it.
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 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.
I'm changing the background colour of the labels dynamically, the width of the cell seems to be static and is working properly in case of 6s only, the background colour fades if the size of the display increases
cell.container.layer.backgroundColor = GetColor().randomColor(indexPath.row).colorWithAlphaComponent(0.5).CGColor
cell.title.layer.backgroundColor = GetColor().randomColor(indexPath.row).colorWithAlphaComponent(0.8).CGColor
New Code// after changing the opacity
// cell.container.layer.backgroundColor = UIColor.blackColor().colorWithAlphaComponent(0.85).CGColor
cell.title.backgroundColor = GetColor().randomColor(indexPath.row).colorWithAlphaComponent(0.5)
Mohit Arya,
I beilieve you have applied Autolayout constraint on the label inside the cell :) If yes please verify if its the same as I have shown below if not please add autolayout constraints properly,
As you are setting the color of the label itself and want it to cover the whole cell setting all the four constraint to 0 is necessary
EDIT:
Now as per your comment, if constraints are same as I have given below your label must be covering the whole cell :)
Then all you have to do is to
[cell.label setBackgroundColor: GetColor().randomColor(indexPath.row).colorWithAlphaComponent(1.0)]
cell.label.opaque = YES;
Check background color (and background color alpha value) for all views in your cell view hierarchy. For example, issue like this can appear if your cell's contentView have background color with alpha < 1, and your label (which size don't fit contentView) have same background color. Thats all what we can say by information you provided.
So, use different colors, or use alpha = 1, or use clear color in label.
I found the solution..the following code was interfering with the UI, I still don't know why the container.bounds is not returning the actual width
container.layer.shadowColor = UIColor.lightGrayColor().CGColor
container.layer.shadowOpacity = 1
container.layer.shadowOffset = CGSizeMake(0, 1);
container.layer.shadowRadius = 2
container.layer.shadowPath = UIBezierPath(rect: container.bounds).CGPath
Due to our designer being a sadist, I have a UITableView with a segmented control that switches between two different types of cells in separate feeds. The cells are dequeued with different identifiers and classes — this all works fine. The cells share a parent but are different sizes and for optimization reasons I set the layer.shadowpath manually in layoutSubviews() of the parent. I need the shadows: designer's wishes.
The issue is that after I switch to the second segment, some of the way down the table there are shadows dangling from what I believe are the cells above. As you can see from the first image, there are two shadows, and if I scroll down to occlude the top-most visible cell the shadow disappears, which leads me to the believe that the shadows are offset. Further scrolling makes these shadows disappear and not reappear again until switching tabs again. The rest of the shadows are fine.
two shadows
scroll down slightly
When switching back to the previous tab, where the cells are taller, there are also shadow issues, but those shadows are too short. As noted, the code that sets the shadow path is in the parent class, and the parent class is responsible for making and laying-out the top-most "card" view that contains the custom subCells.
I do everything programmatically: setting up the views and the Autolayout. Currently cell heights are hard-coded.
I'm not sure what information is relevant as I am completely at a loss, so here is how I set the shadowPath.
override func layoutSubviews() {
super.layoutSubviews()
cardView.layer.shadowPath = UIBezierPath(rect: cardView.bounds).CGPath
}
For simplicity the card is layout out in the contentView with the following visual format:
"V:|-marginV-[card]-marginV-|"
"H:|-marginH-[card]-marginH-|"
For whatever reason, even though I was using separate classes and separate reuseIdentifiers, the first reused cells just out of the view port were still sized as the tall cells in the other segment. When I changed
let cell = tableView.dequeueReusableCellWithIdentifier(booksReuseIdentifier) as! ProfileBookCell
to include the indexPath as
let cell = tableView.dequeueReusableCellWithIdentifier(booksReuseIdentifier, forIndexPath: indexPath) as! ProfileBookCell the recycling issue was remedied and bounds were properly computed. I tried layoutIfNeeded in a dozen different places to no effect, but this fixed it.
I had the same exact problem and I tried the current marked solution but that, nor anything else seemed to work. After trying so many other things I finally tried moving my add shadow code inside the layoutSubviews function of my subclassed UITableViewCell and it finally worked! I think this worked because the cell's final size isn't always calculated properly until the layouSubviews call and it needs the proper size to draw the shadow.
override func layoutSubviews() {
super.layoutSubviews()
addShadow(cell: self)
}
private func addShadow(cell:UITableViewCell) {
cell.layer.shadowOffset = CGSize(width:1, height:1)
cell.layer.shadowColor = UIColor.black.cgColor
cell.layer.shadowRadius = 1
cell.layer.shadowOpacity = 0.6
cell.clipsToBounds = false
let shadowFrame: CGRect = (cell.layer.bounds)
let shadowPath: CGPath = UIBezierPath(rect: shadowFrame).cgPath
cell.layer.shadowPath = shadowPath
}