Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Issue in setting corner radius of view inside cell?

I have a custom UITableView cell.I am setting it's bottom left & bottom right corner radius.I am setting corner radius in cellForAtindexPath.Below is the code for that

if indexPath.row == 9 {
  recipeInfoCell.outerView.roundCorners(corners: [.bottomLeft, .bottomRight], radius: 10)
  recipeInfoCell.layoutSubviews()
  recipeInfoCell.layoutIfNeeded()
} else  {
  recipeInfoCell.outerView.roundCorners(corners: [.bottomLeft, .bottomRight], radius: 0)
  recipeInfoCell.layoutSubviews()
}

Now when i first launch the tableview then it does not set any corner radius. But when i scroll again then it is setting the corner radius.

I have created an extension of UIView in which there is one function which is setting the corner radius

func roundCorners(corners: UIRectCorner, radius: CGFloat) {
  let path = UIBezierPath(roundedRect: self.bounds, byRoundingCorners: corners, cornerRadii: CGSize(width: radius, height: radius))
  let mask = CAShapeLayer()
  mask.path = path.cgPath
  self.layer.mask = mask
}

Please tell how do i resolve this ?

like image 480
TechChain Avatar asked May 10 '17 08:05

TechChain


People also ask

How do you give a corner radius to a cell in Swift?

Rounded Corners on a UICollectionViewCell To apply rounded corners, set a cornerRadius on both the layer and contentView. layer properties. On the contentView. layer , set masksToBounds to true so the contentView contents are clipped to the rounded corners.


2 Answers

I do not think it is a good idea to set corner radius in cellForRow atIndexPath. The reason being, this function is called many times during the lifetime of UITableView and you only need to set the corner radius only once and that too when the cell is initialised. Changing the corner radius based on indexPath will also affect the UITableView's performance.

A better way to this would be to create two cells, one with corner radius as 0 and another with 10 and the use those cells based on indexPath.

Then you can put your cornerRadius set logic in layoutSubview function in your custom cell.

If you want to do it in your tableView methods only, the correct way is to do it in willDisplayCell because after that call, cell's layoutSubviews function in called.

func tableView(_ tableView: UITableView, willDisplay cell: UITableViewCell, forRowAt indexPath: IndexPath) {
    if indexPath.row % 2 == 0 {
        let path = UIBezierPath(roundedRect: cell.contentView.bounds, byRoundingCorners: [.bottomRight, .bottomLeft], cornerRadii: CGSize(width: 10, height: 10))
        let mask = CAShapeLayer()
        mask.path = path.cgPath
        cell.contentView.layer.mask = mask
    } else {
        let path = UIBezierPath(roundedRect: cell.bounds, byRoundingCorners: [.bottomRight, .bottomLeft], cornerRadii: CGSize(width: 0, height: 0))
        let mask = CAShapeLayer()
        mask.path = path.cgPath
        cell.contentView.layer.mask = mask
    }
}

UPDATE: May 19, 2017

The above concept will work fine when the view that you want to round and put shadow on is the same size as the cell's content view. But if it is anything different than that, it won't work.

The reason for the above statement is that at the time when willDisplayCell is called, where the above code is using cell.contentView.bounds, the other views are not calculated yet. So when we will be using another view, we will have to use that view's bounds to calculate the mask's frame which we will be different from the actual one.

After reading up on this a bit, I found out that, to do this kind of a thing is by overriding draw(_ rect: CGRect) function of UITableViewCell. Because at this point, the view's size has been properly calculated and we can create a correct frame.

Below is the code from custom UITableViewCell class:

var shadowLayer = CAShapeLayer()

override func draw(_ rect: CGRect) {
    let path = UIBezierPath(roundedRect: self.outerView.bounds, byRoundingCorners: [.bottomRight, .bottomLeft], cornerRadii: CGSize(width: 10, height: 10))
    let mask = CAShapeLayer()
    mask.path = path.cgPath
    self.outerView.layer.mask = mask
    // Handle Cell reuse case        
    shadowLayer.removeFromSuperlayer()

    shadowLayer.shadowPath = path.cgPath
    shadowLayer.frame = self.outerView.layer.frame
    print(shadowLayer.frame)
    shadowLayer.shadowOffset = CGSize(width: 0, height: 0)
    shadowLayer.shadowColor = UIColor.black.cgColor
    shadowLayer.shadowOpacity = 0.9
    self.contentView.layer.insertSublayer(shadowLayer, below: self.outerView.layer)
    super.draw(rect)
}
like image 122
kerry Avatar answered Oct 21 '22 04:10

kerry


put round corner code in main queue like this :

if indexPath.row == 9 { dispatch_async(dispatch_get_main_queue(),{
recipeInfoCell.outerView.roundCorners(corners: [.bottomLeft, .bottomRight], radius: 10)
   })} else{
 dispatch_async(dispatch_get_main_queue(),{
recipeInfoCell.outerView.roundCorners(corners: [.bottomLeft, .bottomRight], radius: 0)
}) }
like image 32
Pradeep Kashyap Avatar answered Oct 21 '22 03:10

Pradeep Kashyap