Tableview单元格边框没有迅速占据全宽

Posted

技术标签:

【中文标题】Tableview单元格边框没有迅速占据全宽【英文标题】:Tableview cell border not occupying full width in swift 【发布时间】:2020-07-29 12:23:55 【问题描述】:

我正在尝试在我的表格视图单元格的所有边上添加一个边框,我能够添加边框,但遇到了一个问题,即右侧的边框没有占据单元格的整个宽度,如截图如下。单元格边框似乎采用了故事板 UI 设置的初始宽度,例如,我已将 UI 设置为 iPhone SE,但如果我在 iPhone 11 上运行,则会出现此问题。似乎是布局未刷新的一些问题。我尝试添加 setNeedsLayout、setNeedsDisplay 和 layoutSubviews,但它们似乎都不起作用。

故事板布局

下面是完整代码

class ViewController: UIViewController 

    var dataSource = [String] ()
    override func viewDidLoad() 
        super.viewDidLoad()
        for index in 1...10 
            dataSource.append("Cell value \(index)")
        
    


extension ViewController: UITableViewDataSource 
    func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int 
        return dataSource.count
    
    
    func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell 
        guard let cell: MyTableViewCell = tableView.dequeueReusableCell(withIdentifier: "MyTableViewCell", for: indexPath) as? MyTableViewCell elsereturn UITableViewCell()
        
        cell.titleLabel.text = dataSource[indexPath.row]
        
        if indexPath.row == 0 
            cell.containerView.addBorder(toEdges: [.left, .top, .right], color: .gray, thickness: 1.0)
         else if indexPath.row == dataSource.count - 1 
            cell.containerView.addBorder(toEdges: .all, color: .gray, thickness: 1.0)
         else 
            cell.containerView.addBorder(toEdges: [.left, .top, .right], color: .gray, thickness: 1.0)
        
        return cell
    


class MyTableViewCell: UITableViewCell 
    @IBOutlet weak var titleLabel: UILabel!
    @IBOutlet weak var containerView: UIView!


extension UIView 
    func addBorder(toEdges edges: UIRectEdge, color: UIColor, thickness: CGFloat) 
        func addBorder(toEdge edges: UIRectEdge, color: UIColor, thickness: CGFloat) 
            let border = CALayer()
            border.backgroundColor = color.cgColor
            switch edges 
            case .top:
                border.frame = CGRect(x: 0, y: 0, width: frame.width, height: thickness)
            case .bottom:
                border.frame = CGRect(x: 0, y: frame.height - thickness, width: frame.width, height: thickness)
            case .left:
                border.frame = CGRect(x: 0, y: 0, width: thickness, height: frame.height)
            case .right:
                border.frame = CGRect(x: frame.width - thickness, y: 0, width: thickness, height: frame.height)
            default:
                break
            
            layer.addSublayer(border)
        
        
        if edges.contains(.top) || edges.contains(.all) 
            addBorder(toEdge: .top, color: color, thickness: thickness)
        
        
        if edges.contains(.bottom) || edges.contains(.all) 
            addBorder(toEdge: .bottom, color: color, thickness: thickness)
        
        
        if edges.contains(.left) || edges.contains(.all) 
            addBorder(toEdge: .left, color: color, thickness: thickness)
        
        
        if edges.contains(.right) || edges.contains(.all) 
            addBorder(toEdge: .right, color: color, thickness: thickness)
        
    

【问题讨论】:

刚刚复制了您的项目,粘贴了代码副本。一切正常(Xcode 11.4 / ios 13.4),所以我假设您忘记在情节提要中添加一些约束。 尝试在情节提要中将视图设置为 iPhone SE 并在 iPhone 11 模拟器/设备上运行 Layer 不知道约束,因此您需要在布局更改时重新创建(重新构建)它们,或者只是子类化容器 UIView 并在 draw(_ rect:) 中手动绘制边框(考虑到重复使用的行,对我来说,这将是更简单的方法) 【参考方案1】:

您可能会发现使用UIView 子类来处理“边缘”要容易得多。

将此类添加到您的项目中:

class BorderedView: UIView 
    
    var edges: UIRectEdge = []
    var color: UIColor = .clear
    var thickness: CGFloat = 0
    
    var shapeLayer: CAShapeLayer!
    
    override class var layerClass: AnyClass 
        return CAShapeLayer.self
    
    
    override init(frame: CGRect) 
        super.init(frame: frame)
        commonInit()
    
    required init?(coder: NSCoder) 
        super.init(coder: coder)
        commonInit()
    
    func commonInit() -> Void 
        shapeLayer = self.layer as? CAShapeLayer
        shapeLayer.fillColor = UIColor.clear.cgColor
    
    
    override func layoutSubviews() 
        super.layoutSubviews()
        
        let pth = UIBezierPath()
        
        if edges.contains(.top) || edges.contains(.all) 
            pth.move(to: CGPoint(x: bounds.minX, y: bounds.minY))
            pth.addLine(to: CGPoint(x: bounds.maxX, y: bounds.minY))
        
        
        if edges.contains(.bottom) || edges.contains(.all) 
            pth.move(to: CGPoint(x: bounds.minX, y: bounds.maxY))
            pth.addLine(to: CGPoint(x: bounds.maxX, y: bounds.maxY))
        
        
        if edges.contains(.left) || edges.contains(.all) 
            pth.move(to: CGPoint(x: bounds.minX, y: bounds.minY))
            pth.addLine(to: CGPoint(x: bounds.minX, y: bounds.maxY))
        
        
        if edges.contains(.right) || edges.contains(.all) 
            pth.move(to: CGPoint(x: bounds.maxX, y: bounds.minY))
            pth.addLine(to: CGPoint(x: bounds.maxX, y: bounds.maxY))
        

        shapeLayer.lineWidth = thickness
        shapeLayer.strokeColor = color.cgColor
        shapeLayer.path = pth.cgPath
    

然后将containerView 的自定义类分配给BorderedView。在您的单元格中正常连接它:

@IBOutlet weak var containerView: BorderedView!

将您的单元格类更改为:

class MyTableViewCell: UITableViewCell 
    @IBOutlet weak var titleLabel: UILabel!
    @IBOutlet weak var containerView: BorderedView!
    
    func configureContainer(toEdges edges: UIRectEdge, color: UIColor, thickness: CGFloat) -> Void 
        containerView.edges = edges
        containerView.color = color
        containerView.thickness = thickness
    


然后,在cellForRowAt 中,而不是调用:

cell.containerView.addBorder(toEdges: [.left, .top, .right], color: .gray, thickness: 1.0)

这样称呼它:

cell.configureContainer(toEdges: [.left, .top, .right], color: .gray, thickness: 1.0)

结果 - tableView 每边插入 8 个点,因此您可以看到左/右边缘:

当tableView/cells改变大小时(比如设备旋转),边缘会自动更新:

【讨论】:

【参考方案2】:

我同意@Asperi 的回答。要么你必须继承它并在drawrect中编写这个方法。或者为了快速解决方案,将 frame.width 更改为 UIScreen.main.bounds.width.Check 它将适用于您当前的要求和当前代码。

【讨论】:

以上是关于Tableview单元格边框没有迅速占据全宽的主要内容,如果未能解决你的问题,请参考以下文章

使用自动布局让文本视图占据整个单元格

calayer 没有根据 tableview 单元格中的 UIView 大小而改变

如何在图像下载和高度约束迅速改变后更新表格视图单元格高度?

“左侧详细信息”样式单元格文本中的详细信息标签被切断-迅速

如何为单元格设置双边框

uitableviewcell 分隔线未全宽显示