UITableViewCell shadows - ios

I'm trying to implement this design but all solutions I have browsed won't work and from what I understand it could be because of the spacing between the cells and the UITableView.
Here's the design:
So basically what I'm trying to achieve is to have shadows from all 4 sides as well as some spacing between each cell and the following cell.
Thanks
Edit:
Here's the code I tried.
let shadowSize : CGFloat = 5.0
let shadowPath = UIBezierPath(rect: CGRect(x: -shadowSize / 2,
y: -shadowSize / 2,
width: self.avatarImageView.frame.size.width + shadowSize,
height: self.avatarImageView.frame.size.height + shadowSize))
self.avatarImageView.layer.masksToBounds = false
self.avatarImageView.layer.shadowColor = UIColor.black.cgColor
self.avatarImageView.layer.shadowOffset = CGSize(width: 0.0, height: 0.0)
self.avatarImageView.layer.shadowOpacity = 0.5
self.avatarImageView.layer.shadowPath = shadowPath.cgPath
Edit 2:
I'd like to point out that all my cell's objects are inside a container UIView. All the above code is applied to this UIView.

You have to make a UIView inside UITableViewCell and work on that view.
FOR SHADOW I AM USING THIS IN UITableViewCell CLASS:-
viewDummy.addShadow() //use from any view
extension UIView {
func addShadow(){
self.layer.shadowColor = UIColor.blackColor().CGColor
self.layer.shadowOpacity = 0.5
self.layer.shadowRadius = 2.0
self.layer.shadowOffset = CGSizeMake(1.0, 1.0)
}
}

func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "cell", for: indexPath)
cell.layer.shadowOffset = CGSize(width: 0, height: 0)
cell.layer.shadowColor = UIColor.black.cgColor
cell.layer.shadowRadius = 5
cell.layer.shadowOpacity = 0.40
cell.layer.masksToBounds = false;
cell.clipsToBounds = false;
return cell
}

Related

Adding a dashed bottom border to table view cell overlaps with text randomly in iOS

I am using the below code to add a dashed custom bottom border to tableview cells. It is now overlapping with content randomly. Sometimes, the border is not getting displayed.
class AppTableCell: UITableViewCell {
var shapeLayer: CAShapeLayer?
var isBorderAdded = false
func isBottomBorderAdded() -> Bool {
return isBorderAdded
}
func getBottomBorderShapeLayer() -> CAShapeLayer {
return self.shapeLayer!
}
func setBottomBorderShapedLayer(_ layer: CAShapeLayer) {
self.shapeLayer = layer
}
}
The extend tableview cell from the above class and calls the below function in func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell method.
func addDashedBottomBorder(to cell: AppTableCell) {
let color = UIColor.init(red: 191/255, green: 191/255, blue: 191/255, alpha: 1.0).cgColor
let shapeLayer:CAShapeLayer = CAShapeLayer()
let frameSize = cell.frame.size
let shapeRect = CGRect(x: 0, y: 0, width: frameSize.width, height: 0)
shapeLayer.bounds = shapeRect
shapeLayer.position = CGPoint(x: frameSize.width/2, y: frameSize.height)
shapeLayer.fillColor = UIColor.clear.cgColor
shapeLayer.strokeColor = color
shapeLayer.lineWidth = 2.0
shapeLayer.lineJoin = CAShapeLayerLineJoin.round
shapeLayer.lineDashPhase = 3.0
shapeLayer.lineDashPattern = [9,6]
shapeLayer.path = UIBezierPath(roundedRect: CGRect(x: 0, y: shapeRect.height, width: shapeRect.width, height: 0), cornerRadius: 0).cgPath
if (cell.isBorderAdded) {
cell.shapeLayer!.removeFromSuperlayer()
}
cell.shapeLayer = shapeLayer
cell.isBorderAdded = true
cell.layer.addSublayer(shapeLayer)
}
How to display dashed bottom border at the end of each cell properly?
Your are adding a sublayer in your cell's layer with a fixed position:
shapeLayer.position = CGPoint(x: frameSize.width/2, y: frameSize.height)
[...]
cell.layer.addSublayer(shapeLayer)
So it doesn't stick to your cell's bottom side.
You could update this layer's position each time the cell's height change, but my suggestion from a performance and simplicity point of view would be use autolayout.
Add a subview at the bottom of your cell, add the constraints to make it stick, and add only once (in awakeFromNib for example if it's designed in IB) the dashedLayer inside.

How to add shadow only for the border?

I want to add shadow around collectionview cells. But the shadow is around the images and labels in the cell, and no shadow around the cell. Does someone know how to work it out?
cell.contentView.layer.cornerRadius = 2.0
cell.contentView.layer.borderWidth = 1.0
cell.contentView.layer.borderColor = UIColor.clear.cgColor
cell.contentView.layer.masksToBounds = true
cell.layer.masksToBounds = false
cell.layer.shadowColor = UIColor.black.cgColor
cell.layer.shadowOpacity = 0.5
cell.layer.shadowOffset = CGSize(width: -1, height: 1)
cell.layer.shadowRadius = 1
Shadow around the content(not the border)
You are applying shadow to contentView directly hence it is not working. You need to take a view inside your contentView, put all your content in this view and give some padding (e.g. 8pt) from all side.
Suppose I have named this view as vwContainer, then:
#IBOutlet weak var vwContainer: UIView!
let shadowPath = UIBezierPath(rect: vwContainer.bounds)
vwContainer.layer.masksToBounds = false
vwContainer.layer.shadowColor = UIColor.blackColor().CGColor
vwContainer.layer.shadowOffset = CGSizeMake(0.0, 5.0)
vwContainer.layer.shadowOpacity = 0.5
vwContainer.layer.shadowPath = shadowPath.CGPath
If you are trying to achieve any other UI than please update your question with image.
extension UIView {
func addShadow(color: UIColor, radius: CGFloat = 1, offset: CGSize) {
self.layoutIfNeeded()
self.layer.masksToBounds = false
self.layer.shadowColor = color.cgColor
self.layer.shadowOpacity = 0.5
self.layer.shadowOffset = offset
self.layer.shadowRadius = radius
self.layer.shadowPath = UIBezierPath(rect: self.bounds).cgPath
}
}
Use it as:
let offset = CGSize(width: -1, height: 1)
cell.addShadow(color: .black, offset: offset)
You need to set background color for the contentView as below
cell.contentView.backgroundColor = .white

UICollectionView Issue

Xcode 10 beta 5, iOS 12.0 16A5339e
I use the UICollectionView inside my app with the following code:
extension MainWindowViewController: UICollectionViewDataSource, UICollectionViewDelegate {
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return itemMenuArray.count
}
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
if let itemCell = collectionView.dequeueReusableCell(withReuseIdentifier: "main_menu_cell", for: indexPath) as? MainWindowCollectionViewCell {
let item = itemMenuArray[indexPath.row]
itemCell.refresh(item)
return itemCell
}
return UICollectionViewCell()
}
And the problem is that method .refresh executes for separate cells when I scroll my CollectionView. So the cell that is out of the screen updates every time I scroll into its direction and causes wrong cell colors sometimes. Are there any ideas how to fix that?
.refresh code (I use that in my custom cell class):
public func refresh(_ menu: Menu) {
Title.text = menu.name
if let image = menu.img {
Image.image = UIImage(named: image)
}
print(SubscriptionTitle.text!)
self.setupCellAppearance(firstColor: UIColor(hexString: (menu.firstColor)!), secondColor: UIColor(hexString: (menu.secondColor)!))
}
setupCellAppearance code:
func setupCellAppearance(firstColor: UIColor, secondColor: UIColor) {
// Setting up the gradient for each cell
clipsToBounds = true
let gradientLayer = CAGradientLayer()
gradientLayer.colors = [firstColor.cgColor, secondColor.cgColor]
gradientLayer.frame = self.bounds
gradientLayer.startPoint = CGPoint(x: 0, y: 0)
gradientLayer.endPoint = CGPoint(x: 1, y: 0)
gradientLayer.cornerRadius = 10.0
self.layer.insertSublayer(gradientLayer, at: 0)
// Setting up the corner radius and shadows for each cell
self.layer.shadowColor = firstColor.cgColor
self.layer.shadowOffset = CGSize(width: 0.0, height: 5.0)
self.layer.shadowRadius = 10
self.layer.shadowOpacity = 0.5
self.layer.masksToBounds = false;
self.layer.shadowPath = UIBezierPath(roundedRect: self.bounds, cornerRadius: self.layer.cornerRadius).cgPath
}
What happening is cellForItemAt reuse the cell so every time cell is reuse which might already having gradient layer with it and you are trying add a new gradient so that creating a different color. So you need to remove the layer if its already there, to remove layer set name property of CAGradientLayer with some unique name and then before inserting in layer check layer with that name already exist, if it exist remove it.
func setupCellAppearance(firstColor: UIColor, secondColor: UIColor) {
//Check gradient is already exist
for layer in self.layer.sublayers ?? [] {
if layer.name == "BGGradient" {
layer.removeFromSuperlayer()
break
}
}
// Setting up the gradient for each cell
clipsToBounds = true
let gradientLayer = CAGradientLayer()
//set name property of gradient layer
gradientLayer.name = "BGGradient"
gradientLayer.colors = [firstColor.cgColor, secondColor.cgColor]
gradientLayer.frame = self.bounds
gradientLayer.startPoint = CGPoint(x: 0, y: 0)
gradientLayer.endPoint = CGPoint(x: 1, y: 0)
gradientLayer.cornerRadius = 10.0
self.layer.insertSublayer(gradientLayer, at: 0)
// Setting up the corner radius and shadows for each cell
self.layer.shadowColor = firstColor.cgColor
self.layer.shadowOffset = CGSize(width: 0.0, height: 5.0)
self.layer.shadowRadius = 10
self.layer.shadowOpacity = 0.5
self.layer.masksToBounds = false;
self.layer.shadowPath = UIBezierPath(roundedRect: self.bounds, cornerRadius: self.layer.cornerRadius).cgPath
}

tableviewCell is cut off from bottom in every cell

Here is my code:
override func tableView(_ tableView: UITableView, willDisplay cell: UITableViewCell, forRowAt indexPath: IndexPath) {
let whiteRoundedView : UIView = UIView(frame: CGRect(x: 10, y: 8, width: self.view.frame.size.width - 20, height: 140))
whiteRoundedView.layer.backgroundColor = CGColor(colorSpace: CGColorSpaceCreateDeviceRGB(), components: [1.0, 1.0, 1.0, 0.9])
whiteRoundedView.layer.masksToBounds = false
whiteRoundedView.layer.cornerRadius = 2.0
whiteRoundedView.layer.shadowOffset = CGSize(width: -1, height: 1)
whiteRoundedView.layer.shadowOpacity = 0.2
whiteRoundedView.layer.borderWidth = 0.5
whiteRoundedView.layer.borderColor = UIColor.orange.cgColor
cell.contentView.backgroundColor = UIColor.clear
cell.contentView.addSubview(whiteRoundedView)
cell.contentView.sendSubview(toBack: whiteRoundedView)
cell.accessoryType = .disclosureIndicator
cell.clipsToBounds = true;
}
Every cell is cut off from the bottom and not showing the complete cell structure.
Any idea?
There is not enough space for the whiteRoundedView over cell height.
Hence, reduce the height <140 of whiteRoundedView while initialization.
let whiteRoundedView : UIView = UIView(frame: CGRect(x: 10, y: 8, width:self.view.frame.size.width - 20, height: YOUR_NEW_HEIGHT))
Your whiteRoundedView should be within the cell content view.
So, try using heightForRowAt indexPath and use the same height for whiteRoundedView in your willDisplay cell

TableView rounded corners and shadow

I have a tableview with three rows. I am trying to make the table rows have rounded corners and also a shadow effect around the entire tableview. For some reason, I cannot make the tableview both have the rounded corners and shadow effect but I could do them separately if I comment out the code responsible for one of the features. Here is the code I am using:
//this is for shadow effect
tableView.backgroundColor = UIColor.clearColor()
tableView.layer.shadowColor = UIColor.darkGrayColor().CGColor
tableView.layer.shadowOffset = CGSize(width: 2.0, height: 2.0
tableView.layer.shadowOpacity = 1.0
tableView.layer.shadowRadius = 2
// This is for rounded corners
tableView.layer.cornerRadius = 10
tableView.layer.masksToBounds = true
You can add your table view to a container view and add drop shadow to that container view:
let containerView:UIView = UIView(frame:CGRect(x: 10, y: 100, width: 300, height: 400))
self.tableView = UITableView(frame: containerView.bounds), style: .Plain)
containerView.backgroundColor = UIColor.clearColor()
containerView.layer.shadowColor = UIColor.darkGrayColor().CGColor
containerView.layer.shadowOffset = CGSize(width: 2.0, height: 2.0)
containerView.layer.shadowOpacity = 1.0
containerView.layer.shadowRadius = 2
// This is for rounded corners
self.tableView.layer.cornerRadius = 10
self.tableView.layer.masksToBounds = true
self.view.addSubview(containerView)
containerView.addSubview(self.tableView)
Edit
Swift 3.0:
let containerView:UIView = UIView(frame:CGRect(x: 10, y: 100, width: 300, height: 400))
self.tableView = UITableView(frame: containerView.bounds, style: .plain)
containerView.backgroundColor = UIColor.clear
containerView.layer.shadowColor = UIColor.darkGray.cgColor
containerView.layer.shadowOffset = CGSize(width: 2.0, height: 2.0)
containerView.layer.shadowOpacity = 1.0
containerView.layer.shadowRadius = 2
self.tableView.layer.cornerRadius = 10
self.tableView.layer.masksToBounds = true
self.view.addSubview(containerView)
containerView.addSubview(self.tableView)
The RDC's answer is good, but for me the result didnt resolve my case, follow is my fix :
//for table view border
tableView.layer.borderColor = UIColor .grayColor().CGColor
tableView.layer.borderWidth = 1.0
//for shadow
let containerView:UIView = UIView(frame:self.tableView.frame)
//dont use clear color,fit blue color
containerView.backgroundColor = UIColor.blueColor()
//shadow view also need cornerRadius
containerView.layer.cornerRadius = 10
containerView.layer.shadowColor = UIColor.lightGrayColor().CGColor
containerView.layer.shadowOffset = CGSizeMake(-10, 10); //Left-Bottom shadow
//containerView.layer.shadowOffset = CGSizeMake(10, 10); //Right-Bottom shadow
containerView.layer.shadowOpacity = 1.0
containerView.layer.shadowRadius = 2
//for rounded corners
tableView.layer.cornerRadius = 10
tableView.layer.masksToBounds = true
self.view.addSubview(containerView)
self.view.addSubview(tableView)
i tried above solution but in my application tableview didSelectRowAt was not working.
use this Extension for UITabeleView
for corner
for shadow
//if u want shadow for all side use (shadowOffset = .zero)
extension UITableView {
func addCorner(){
self.layer.cornerRadius = 15
self.clipsToBounds = true
}
func addShadow(){
self.layer.shadowColor = UIColor.lightGray.cgColor
self.layer.shadowRadius = 5
self.layer.shadowOpacity = 0.5
self.layer.shadowOffset = .zero
self.layer.masksToBounds = false
}
}
How to use::
self.tableView.addCorner()
self.tableView.addShadow()
Thanks to #beyowulf
I have upgraded for me with Swift 2.2, to
set Border,
Rounded corner and
Drop shadow to the table view
//for table view border
tableView.layer.borderColor = UIColor .grayColor().CGColor
tableView.layer.borderWidth = 1.0
//for shadow
let containerView:UIView = UIView(frame:self.tableView.frame)
containerView.backgroundColor = UIColor.clearColor()
containerView.layer.shadowColor = UIColor.lightGrayColor().CGColor
containerView.layer.shadowOffset = CGSizeMake(-10, 10); //Left-Bottom shadow
//containerView.layer.shadowOffset = CGSizeMake(10, 10); //Right-Bottom shadow
containerView.layer.shadowOpacity = 1.0
containerView.layer.shadowRadius = 2
//for rounded corners
tableView.layer.cornerRadius = 10
tableView.layer.masksToBounds = true
self.view.addSubview(containerView)
containerView.addSubview(tableView)
result looks like

Resources