【问题标题】:UITableViewCell drawRect bottom border disappears on insertRowUITableViewCell drawRect 底部边框在 insertRow 上消失
【发布时间】:2026-01-22 02:20:08
【问题描述】:

我有一个自定义 UITableViewCell,我使用 drawRect 绘制一个简单的底部边框:

override func drawRect(rect: CGRect) {   
   let context = UIGraphicsGetCurrentContext()
   CGContextMoveToPoint(context, CGRectGetMinX(rect), CGRectGetMaxY(rect))
   CGContextAddLineToPoint(context, CGRectGetMaxX(rect), CGRectGetMaxY(rect))
   CGContextSetStrokeColorWithColor(context, UIColor(netHex: 0xEFEEF4).CGColor)
   CGContextSetLineWidth(context, 2)
   CGContextStrokePath(context)
}

这非常有效。但是,当我插入带有动画的行时,所有单元格的边框都会消失,并在插入动画完成时再次出现:

tableView.insertRowsAtIndexPaths([NSIndexPath(forRow: cells.count - 1, inSection: 0)], withRowAnimation: UITableViewRowAnimation.Fade)

知道如何避免这种情况吗?

【问题讨论】:

  • 我认为你可以通过额外的子层(具有背景颜色和高度的 CALayer)实现相同的视觉效果,并且完全避免绘制。但这当然不能回答你的问题:)
  • @sage444 如果它是一个可行的替代方案,请将其添加为答案。
  • 我们可以在故事板本身的单元格底部有一个 2 像素的简单 uiimageview..并在那里提供一种颜色...这将充当边框。还有,您是否正在调用单元格 setNeedsDisplay.. 以便再次调用 drawRect 方法?

标签: ios swift uitableview swift2


【解决方案1】:

如果您只想使用 CALayers,假设您的 TableView 覆盖了设备的整个宽度,您可以在 tablecell 的 awakeFromNib 中尝试此代码。

override func awakeFromNib() {
    super.awakeFromNib()
    let borderLayer = CALayer()
    let lineHeight:CGFloat = 2
    borderLayer.frame = CGRect(x: 0, y: self.frame.height - lineHeight , width: UIScreen.mainScreen().bounds.width, height: lineHeight)
    borderLayer.backgroundColor = UIColor.redColor().CGColor
    self.layer.addSublayer(borderLayer)
}

你会得到如下输出:

同时让你的 tableview 分隔符颜色清除

self.tableView.separatorColor = UIColor.clearColor()

这样它就不会与您的图层重叠。
我可以观察到,现在每当插入新行时,单元格的边界都不会消失。

或者
我们可以在单元故事板中使用 UIImageView 并提供具有以下约束的颜色。
添加 UIImageView

为 UIImageView 添加约束

我们完成了!


还有一个alternate解决方案可以使用Bezier Paths

实现这一目标
 override func awakeFromNib() {
    super.awakeFromNib()
    let line = CAShapeLayer()
    let linePath = UIBezierPath()
    linePath.moveToPoint(CGPointMake(0, self.frame.height))
    linePath.addLineToPoint(CGPointMake(UIScreen.mainScreen().bounds.width, self.frame.height))
    line.lineWidth = 3.0
    line.path = linePath.CGPath
    line.strokeColor = UIColor.redColor().CGColor
    self.layer.addSublayer(line)
 }

这也会产生相同的输出。

编辑:

如果我们没有为单元格使用故事板或笔尖并以编程方式创建单元格,那么我们可以执行如下解决方法:

在您的 CustomTableViewCell 类中创建一个属性

var borderLayer:CALayer!

现在CustomTableViewCell 类中有一个叫layoutSubviews 的方法

override func layoutSubviews() {
    if(borderLayer != nil) {
        borderLayer.removeFromSuperlayer()
    }
    borderLayer = CALayer()
    let lineHeight:CGFloat = 2
    borderLayer.frame = CGRect(x: 0, y: self.frame.height - lineHeight , width: UIScreen.mainScreen().bounds.width, height: lineHeight)
    borderLayer.backgroundColor = UIColor.redColor().CGColor
    self.layer.addSublayer(borderLayer)
}

试试这个。

【讨论】:

  • 这也是很好的答案,但为什么你不添加 UIImageView 替代品而不是使用我的想法?
  • 见我也使用 CALayers 和 BezierPaths 。对于 UIImageView 部分,它比添加图层要容易得多,而且复杂度也较低。 UIImageView 的开销也很小。我也会在答案中更新替代方案。
  • 期待看到 BezierPath
  • 你的答案似乎是关于分隔符,但是关于按钮边框的问题
  • 你确定是关于按钮吗?它关于带有底部边框的表格单元
【解决方案2】:

这不是直接的答案,只是我的建议如何在不绘制的情况下实现相同的视觉效果。

查看示例代码和结果图片

@IBOutlet weak var button: UIButton!
override func viewDidLoad() {
    super.viewDidLoad()

    let layer = CALayer()
    let lineHeight:CGFloat = 2
    layer.frame = CGRect(x: 0, y: button.bounds.height - lineHeight , width: button.bounds.width, height: lineHeight)
    layer.backgroundColor = UIColor(colorLiteralRed: 0xEF/255.0, green: 0xEE/255.0, blue: 0xF4/255.0, alpha: 1).CGColor
    button.layer.addSublayer(layer)
}

在 IB 中配置的按钮和背景视图颜色。

【讨论】:

  • 我看到了问题。我不能把它放到我的 UITableViewCell 类中,因为它没有 viewDidLoad。当我将它放入类的init函数时,自动布局尚未计算高度和宽度。
  • 哦,我用这个方法只是个例子,你可以在 awakeFromNib 或者你自定义的 setData 方法中做到这一点
  • 为什么要使事情复杂化..只需在情节提要单元格本身中添加一个简单的 UIView 或 uiimage 视图 2 像素,其高度 2 像素固定,底部约束为 0,左右为 0.. 就是这样。 .
  • @RajanMaheshwari 你部分正确,但 UIView 与 CALayer 不太一样,在 tableViewCell 中会增加开销
  • @sage444 这就是为什么我写了我们可以使用 UIImageView 而不是 UIView.. 这样开销会非常少
最近更新 更多