【问题标题】:Issue in setting corner radius of view inside cell?在单元格内设置视角半径的问题?
【发布时间】:2017-05-10 08:50:04
【问题描述】:

我有一个自定义的UITableView 单元格。我正在设置它的左下角和右下角半径。我在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
}

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

【问题讨论】:

  • 我正在做,但问题是创建单元格时不显示角半径。当我滚动表格视图时,只设置角半径
  • 你第二次圆角半径,这意味着它不是圆角半径问题。它的表格视图问题。因此,请检查单元格中的条件以查找索引路径处的行。
  • 但是当我像 view.cornerRadius = 10 这样设置角半径时,它就可以正常工作了
  • 你试过把这段代码放入“willDisplayCell”吗?也将背景颜色修改放在那里。 developer.apple.com/reference/uikit/uitableviewdelegate/…

标签: ios uitableview cornerradius


【解决方案1】:

我认为在 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的时候,其他的views还没有计算出来。因此,当我们将使用另一个视图时,我们将不得不使用该视图的边界来计算我们将与实际不同的蒙版框架。

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

以下是自定义 UITableViewCell 类的代码:

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

【讨论】:

  • 我无法采用这种方法。
  • 你没有得到什么部分?
  • 我不想使用其他单元格,因为我已经在 tableview 中使用了太多单元格。这可能会解决我的问题,但我想知道我的代码有什么问题。当我设置只有通过 bazier 路径的圆角半径才会遇到问题。当我在没有 bazier 路径的情况下设置圆角半径时,我的代码工作正常。我将按照你的方法来确保这是否是解决我的问题的方法
  • 我试过你的方法,但这对我不起作用
  • 即使我添加了角半径以在 awakefromnib 中查看,也没有在第一次设置中设置角半径
【解决方案2】:

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

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

【讨论】:

    【解决方案3】:

    尝试在您的自定义UITableViewCelllayoutSubviews() 中编写这些代码行

    override func layoutSubviews() {
      super.layoutSubviews()
      self.outerView.roundCorners(corners: [.bottomLeft, .bottomRight], radius: 10)
    }
    

    【讨论】:

    • 对不起,你想在评论中说什么?你能说得具体点吗?
    • 我就是为什么这段代码在 awakefromnib 中不起作用。为什么我需要重写这个方法
    • 因为在 awakefromnib 没有加载子视图的框架,这就是原因。
    • 这里的outerView是什么?由于该引用,它不会编译。 “没有成员‘outerView’”
    【解决方案4】:

    为了快速获取它,我只使用创建 UIButton 的一个子类,如下所示

    (在项目的任何 .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 类,并为该视图的属性检查器中的属性提供所需的值

    在故事板中

    1) 像这样的视图类

    2) 像这样设置属性

    3) 这将像这样在设计中显示视图

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

    【讨论】:

    • 我的要求和这个不一样
    【解决方案5】:

    如果我理解正确,您希望特定单元格转角。这是我的解决方案。虽然我有点晚了,但我试图帮助别人。 :) 我刚刚将我的解决方案添加为图片。

    第 1 步:

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

    以下是圆角左下角和右下角的代码。抱歉编码风格不佳:

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

    下面是关键时刻:

    【讨论】:

      【解决方案6】:

      我参考了 (https://stackoverflow.com/a/44067058/2781088) 并修改了代码,现在它对我有用:

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

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

      【讨论】:

        【解决方案7】:

        这对我有用:

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

        【讨论】:

          【解决方案8】:

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

          //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 替换为您希望在单元格/视图中四舍五入的 UIView 子类

          【讨论】:

            猜你喜欢
            • 2021-03-02
            • 1970-01-01
            • 1970-01-01
            • 2016-06-14
            • 2016-03-31
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            相关资源
            最近更新 更多