在UITableViewCell内的不同大小的UIView上放置一个遮罩层

时间:2017-10-17 10:56:50

标签: ios swift uitableview uibezierpath cashapelayer

我有一个UITableView,其单元格包含一个子视图,我需要在其上执行三项操作:

  1. 在运行时更改其宽度约束,具体取决于特定于此单元格的对象内的值
  2. 根据相同的值更改背景颜色
  3. 围绕视图的左上角和左下角,但保持右侧的角落(因此layer.cornerRadius不可选)
  4. 我在自定义UITableViewCell子类中使用以下代码,仅在视图的一侧实现圆角效果,我从tableView:cellForRowAt:调用:

    func roundLeadingEdgesOfBar() {
        let roundedLayer = CAShapeLayer()
        roundedLayer.bounds = viewInQuestion.frame
        roundedLayer.position = viewInQuestion.center
        roundedLayer.path = UIBezierPath(roundedRect: viewInQuestion.bounds,
                                         byRoundingCorners: [.topLeft, .bottomLeft],
                                         cornerRadii: CGSize(width: 2, height: 2)).cgPath
        viewInQuestion.layer.mask = roundedLayer
        print("frame: \(viewInQuestion.frame)")
    }
    

    然而,当我运行此代码时,我看到的是这样的效果: enter image description here

    上面代码中的print语句会产生以下输出,表示viewInQuestion每次在屏幕上清晰显示时都没有相同的框架:

    frame: (175.0, 139.5, 200.0, 5.0)
    frame: (175.0, 139.5, 200.0, 5.0)
    frame: (175.0, 139.5, 200.0, 5.0)
    frame: (175.0, 139.5, 200.0, 5.0)
    

    所以我假设在调用此函数时,视图上的宽度约束尚未呈现。当我向上滚动整个表视图直到所有单元格都不在视图中,然后将它们滚动回视图时,一切看起来都正确并且打印的帧都是不同的,就像我期望的那样:

    frame: (136.5, 79.5, 238.5, 5.0)
    frame: (169.5, 79.5, 205.5, 5.0)
    frame: (226.0, 79.5, 149.0, 5.0)
    frame: (247.5, 79.5, 127.5, 5.0)
    

    我已经在SO上多次阅读,以执行依赖于layoutSubviews内部应用的约束的代码,但这给了我相同的结果。我甚至尝试在roundLeadingEdgesOfBar内拨打tableView:willDisplay:forRowAt:,但无济于事。

    我还发现this response to a similar problem建议将掩码图层代码放在drawRect:中。这实际上为我解决了99%的问题(不考虑性能问题),但是仍然存在极端情况(没有双关语)留给非常长的表视图,我仍然看到错误的行为。

    我的最后一招是通过performSelector调用我的舍入功能,延迟时间为0.00001,这样你就可以在屏幕上看到错误大约一秒然后消失 - 这仍然远非理想的行为,更不用说我必须为它编写的糟糕代码了。

    有没有办法使用正确的运行时框架在UITableViewCell内的视图上可靠地应用形状图层?

2 个答案:

答案 0 :(得分:2)

我认为你应该做的是,

  1. cellForRowAtIndexPath中设置与当前对象相关的属性,尝试在该特定值的设置器中设置约束。
  2. 致电setNeedsLayout,以便日后致电layoutIfNeeded - > layoutSubviews
  3. layoutSubviews中,设置圆角。
  4. 我希望这会对你有所帮助。

答案 1 :(得分:2)

而不是调用函数来绕过边缘,"我建议创建一个UIView子类,让它处理舍入。

例如:

class BulletBar: UIView {

    override func layoutSubviews() {

        let roundedLayer = CAShapeLayer()

        roundedLayer.frame = bounds

        roundedLayer.path = UIBezierPath(roundedRect: bounds,
                                         byRoundingCorners: [.topLeft, .bottomLeft],
                                         cornerRadii: CGSize(width: 2, height: 2)).cgPath
        layer.mask = roundedLayer

    }

}

现在,设置"栏的等级"细胞中的子视图到BulletBar。使用约束将其固定在右侧和底部,并约束高度和宽度。为宽度约束创建IBOutlet,然后根据需要设置barWidthConstraint.constant

班级本身将处理四舍五入。

结果:

enter image description here