1

I'm getting one issue with UICollectionView Cell. i'm try to give only 2 side corner radius to UIView with below code. i face below issue. Any suggestion could be appreciate. Thank you

func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
        let cell : FeaturedCell = collectionView.dequeueReusableCell(withReuseIdentifier: "FeaturedCell", for: indexPath) as! FeaturedCell
        let objModel = arrSearch[indexPath.row]
        cell.lblproducttitle.text = "\(objModel.Name!) \n$\(objModel.price!)"
        cell.imgproduct.sd_setImage(with: URL(string: objModel.imgUrl), placeholderImage: UIImage(named: "logo"), options: .refreshCached, completed: nil)

        let mask = CAShapeLayer()
        mask.bounds = cell.productnamevw.frame
        mask.position = cell.productnamevw.center
        mask.backgroundColor = cell.productnamevw.backgroundColor?.cgColor

        let path = UIBezierPath(roundedRect: cell.productnamevw.bounds, byRoundingCorners: [.bottomLeft , .bottomRight], cornerRadii: CGSize(width: 10, height: 10))
        mask.path = path.cgPath
        cell.productnamevw.layer.mask = mask
        cell.productnamevw.layer.masksToBounds = true
        return cell

    }

Issue image

Expectation Image

Bhavesh Nayi
  • 705
  • 4
  • 15
Himanshu Moradiya
  • 4,769
  • 4
  • 25
  • 49
  • @HimanshuMoradiya How upper 2 corner are rounded ? Add your view hierarchy and its sequence. – dahiya_boy Apr 24 '19 at 06:52
  • try using `cell.contentView` instead of just `cell` – iOSer Apr 24 '19 at 06:53
  • what's your iOS version? – Ming Chu Apr 24 '19 at 07:03
  • @Himanshu Moradiya You don't need to make corner radius to you subview (that is in gray color). You just set "clipbounds" to true of your container view. Do this only if your container's corners are the same as your child view has. – Sandip Gill Apr 24 '19 at 07:18
  • This is probably the same problem that I described [in this answer](https://stackoverflow.com/a/36092506/77567) and [in this answer](https://stackoverflow.com/a/33050709/77567): the view (`cell.productnamevw` in this case) hasn't been set to its final size when you create the mask path, so `cell.productnamevw.bounds` has the wrong size. However, I'm not marking this question as a duplicate because, after I wrote those answers, iOS 11 added the `maskedCorners` property to `CALayer`. Setting `maskedCorners` (as several answers here suggest) is a simpler solution. – rob mayoff Apr 24 '19 at 07:30
  • in my case i m not using .xib file i just create on UitableviewCell and i use this cell more then 2 diffrent color with different requirement – Himanshu Moradiya Apr 24 '19 at 07:40

3 Answers3

3

You may want to try the following code to handle diff iOS version

  1. Add the extension for UIView, you can modify it as your need.
extension UIView {
  func roundCorners(corners: UIRectCorner, radius: CGFloat) {
        if #available(iOS 11.0, *) {
            let cornerMasks = [
                corners.contains(.topLeft) ? CACornerMask.layerMinXMinYCorner : nil,
                corners.contains(.topRight) ? CACornerMask.layerMaxXMinYCorner : nil,
                corners.contains(.bottomLeft) ? CACornerMask.layerMinXMaxYCorner : nil,
                corners.contains(.bottomRight) ? CACornerMask.layerMaxXMaxYCorner : nil,
                corners.contains(.allCorners) ? [CACornerMask.layerMinXMinYCorner, CACornerMask.layerMaxXMinYCorner, CACornerMask.layerMinXMaxYCorner, CACornerMask.layerMaxXMaxYCorner] : nil
                ].compactMap({ $0 })

            var maskedCorners: CACornerMask = []
            cornerMasks.forEach { (mask) in maskedCorners.insert(mask) }

            self.clipsToBounds = true
            self.layer.cornerRadius = radius
            self.layer.maskedCorners = maskedCorners
        } else {
            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
        }
    }
}
  1. use the function like that:
cell.productnamevw.roundCorners(corners: [.bottomLeft, .bottomRight], radius: 10)

One more thing, for your case, I would recommend you setup the cell in the cell itself

class FeaturedCell: UICollectionViewCell {

    @IBOutlet private weak var productnamevw: UIView!

    override func awakeFromNib() {
        super.awakeFromNib()

        self.productnamevw.roundCorners(corners: [.bottomLeft, .bottomRight], radius: 10)
    }

    override func layoutSubviews() {
        super.layoutSubviews()

        self.productnamevw.roundCorners(corners: [.bottomLeft, .bottomRight], radius: 10)

    }
}
Ming Chu
  • 1,315
  • 15
  • 13
  • 1
    This will not work because the view hasn't been set to its final size when `awakeFromNib` is called. You need to compute the mask path in the `layoutSubviews` method of `productnamevw`. – rob mayoff Apr 24 '19 at 07:33
  • your answer is correct but when i load first time its show half result and when i scroll down and come back on top then its working well – Himanshu Moradiya Apr 24 '19 at 07:36
  • @HimanshuMoradiya yes, as robmayoff said, the view hasn't been set to final size when awakeFromNib. I updated the code, hope this help :) – Ming Chu Apr 24 '19 at 07:39
2

Note that this only works for iOS 11.0+

yourview.layer.maskedCorners = [.layerMaxXMaxYCorner, .layerMinXMaxYCorner, .layerMinXMinYCorner]
Radhe Yadav
  • 112
  • 11
1

For Swift 4+ & iOS 11.0 later, this will work:

    - For top left corner = [.layerMinXMinYCorner]

    - For top right corner = [.layerMaxXMinYCorner]

    - For bottom left corner = [.layerMinXMaxYCorner]

    - For bottom right corner = [.layerMaxXMaxYCorner]

According to this your code should look like this:

    cell.productnamevw.layer.cornerRadius = 10   //or whatever you want to give
    cell.productnamevw.layer.maskedCorners = [. layerMinXMaxYCorner, . layerMaxXMaxYCorner]
Suhail
  • 324
  • 1
  • 15