在单元格内设置角视野半径的问题?

Issue in setting corner radius of view inside cell?

我有一个自定义 UITableView cell.I 我正在设置它的左下角和右下角 radius.I 我正在 cellForAtindexPath 设置圆角半径。下面是代码

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()
}

现在,当我第一次启动 tableview 时,它没有设置任何圆角半径。但是当我再次滚动时,它正在设置角半径。

我创建了 UIView 的扩展,其中有一个函数用于设置圆角半径

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
}

请告诉我如何解决这个问题?

为了在 swift 中获取它,我只使用创建一个 UIButton 的子class,如下所示

(在项目的任何 .swift 文件中)

//MARK: Custom Class for UIView
open class CustomView: UIView {
    open func drawViewsForRect(_ rect: CGRect) {
        fatalError("\(#function) must be overridden")
    }

    open func updateViewsForBoundsChange(_ bounds: CGRect) {
        fatalError("\(#function) must be overridden")
    }

}

然后在相同或不同的 .swift 文件中定义以下方法,如下所示

    //MARK: - UIView Property Class
@IBDesignable open class CView : CustomView{

    @IBInspectable dynamic open var borderColor: UIColor = UIColor.clear{
        didSet{
            updateBorderColor()
        }
    }

    @IBInspectable dynamic open var borderWidth: CGFloat = 1.0{
        didSet{
            updateBorderWidth()
        }
    }

    @IBInspectable dynamic open var cornerRadius: CGFloat = 0.0{
        didSet{
            updateBorderRadius()
        }
    }

    @IBInspectable dynamic open var shadowColor: UIColor?{
        didSet{
            updateShadowColor()
        }
    }

    @IBInspectable dynamic open var shadowRadius: CGFloat = 0.0{
        didSet{
            updateShadowRadius()
        }
    }

    @IBInspectable dynamic open var shadowOpacity: Float = 0.0{
        didSet{
            updateShadowOpacity()
        }
    }

    @IBInspectable dynamic open var shadowOffSet: CGSize = CGSize(width: 0.0, height: 0.0){
        didSet{
            updateShadowOffset()
        }
    }

    //Update Borders Properties
    open func updateBorderColor(){
        self.layer.borderColor = borderColor.cgColor
    }
    open func updateBorderRadius(){
        self.layer.cornerRadius = cornerRadius
    }
    open func updateBorderWidth(){
        self.layer.borderWidth = borderWidth
    }

    //Update Shadow Properties
    open func updateShadowColor(){
        self.layer.shadowColor = shadowColor?.cgColor
        self.clipsToBounds = false;
        self.layer.masksToBounds = false;
    }
    open func updateShadowOpacity(){
        self.layer.shadowOpacity = shadowOpacity
        self.clipsToBounds = false;
        self.layer.masksToBounds = false;
    }
    open func updateShadowRadius(){
        self.layer.shadowRadius = shadowRadius
        self.clipsToBounds = false;
        self.layer.masksToBounds = false;
    }
    open func updateShadowOffset(){
        self.layer.shadowOffset = CGSize(width: shadowOffSet.width, height: shadowOffSet.height)
        self.layer.shadowColor = shadowColor?.cgColor
        self.clipsToBounds = false;
        self.layer.masksToBounds = false;
    }
}

然后只需在设计时在故事板中为任何视图控制器分配 CView class,并在该视图的属性检查器中为该视图的属性提供所需的值

在情节提要中

1) Class 的视图是这样的

2) 像这样设置属性

3) 这将像这样显示设计的侧面视图

有了这个,您甚至可以直接在您的设计构建器中看到阴影或圆角半径,即在故事板视图的侧面,如第三张图片。

我认为在 cellForRow atIndexPath 中设置角半径不是一个好主意。原因是,这个函数在 UITableView 的生命周期中被调用了很多次,你只需要设置一次圆角半径,并且在单元格初始化时也是如此。根据 indexPath 改变圆角半径也会影响 UITableView 的性能。

更好的方法是创建两个单元格,一个角半径为 0,另一个角半径为 10,并根据 indexPath 使用这些单元格。

然后你可以把你的cornerRadius设置逻辑放在自定义单元格的layoutSubview函数中。

如果您只想在 tableView 方法中执行此操作,正确的方法是在 willDisplayCell 中执行此操作,因为在该调用之后,将调用单元格的 layoutSubviews 函数。

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
    }
}

更新:2017 年 5 月 19 日

当您要圆角和放置阴影的视图与单元格的内容视图大小相同时,上述概念将正常工作。但是,如果它与此不同,它将不起作用。

上面的说法是因为在调用willDisplayCell的时候,上面的代码使用的是cell.contentView.bounds,其他的view还没有计算出来。因此,当我们将使用另一个视图时,我们将不得不使用该视图的边界来计算与实际不同的遮罩框架。

在仔细阅读了这篇文章之后,我发现,做这种事情是通过重写 UITableViewCell 的 draw(_ rect: CGRect) 函数。因为此时,视图的大小已经正确计算,我们可以创建正确的框架。

下面是来自自定义 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)
}

尝试在您的自定义 UITableViewCell

layoutSubviews() 中编写这些代码行
override func layoutSubviews() {
  super.layoutSubviews()
  self.outerView.roundCorners(corners: [.bottomLeft, .bottomRight], radius: 10)
}

像这样将圆角代码放入主队列中:

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)
}) }

如果我理解正确的话,你想要一个特定的单元格圆角。这是我的 solution.Though 我来晚了,但我尽力帮助别人。 :) 我刚刚将我的解决方案添加为图片。

第 1 步:

创建了自定义 Cell 并执行了一些必要的步骤。

下面是圆形左下角和底部的代码 right.Sorry 糟糕的编码风格:

下面是我的视图控制器的配置,用于显示带有圆形单元格的 tableView。

下面是关键时刻:

我参考了 () 并修改了代码,现在它对我有用了:

将以下代码添加到您的自定义单元格class:

enum cellStyle: Int {
    case Normal = 0, Rounded
}

class CustomTableCell:UITableViewCell {
    var cellType: Int = 0 {
        didSet {
            let maskLayer = CAShapeLayer()
            let cell: cellStyle = cellStyle(rawValue: cellType)!
            
            switch cell {
            case .Normal:
                let normal = UIBezierPath(roundedRect: self.viewMain.bounds, byRoundingCorners: [.bottomLeft, .bottomRight], cornerRadii: CGSize(width: 0, height: 0))
                
                maskLayer.path = normal.cgPath
                self.viewMain.layer.mask = maskLayer
            case .Rounded:
                let rounded = UIBezierPath(roundedRect: self.viewMain.bounds, byRoundingCorners: [.bottomLeft, .bottomRight], cornerRadii: CGSize(width: 10, height: 10))
                
                maskLayer.path = rounded.cgPath
                self.viewMain.layer.mask = maskLayer
            }
        }
    }
}

在您的 ViewController->cellForRowAt --- 在主队列中调用以下代码

DispatchQueue.main.async {
            if totalRows == index + 1 { //write your condition
                cell.cellType = cellStyle.Rounded.rawValue
            } else {
                cell.cellType = cellStyle.Normal.rawValue
            }
            cell.layoutSubviews()
            cell.layoutIfNeeded()
        }

这对我有用:

view.clipsToBounds = true
view.layer.cornerRadius = value
view.layer.maskedCorners = [.layerMaxXMaxYCorner, .layerMinXMaxYCorner]

根据我的经验,这对我来说是让动态大小的图层正常工作的方法。

//Inside the cell or the view class
override func layoutSublayers(of layer: CALayer) {
    super.layoutSublayers(of: layer)
    
    if layer === self.layer {
        //Do any dynamic-layer update here
        myViewToRound.layer.cornerRadius = myViewToRound.bounds.width/2
    }
}

在这里,将 myViewToRound 替换为您希望在 cell/view

中四舍五入的 UIView 子类