繁体   English   中英

如何从 UIBezierPath 创建一个 IBDesignable 自定义 UIView?

[英]How to create an IBDesignable custom UIView from a UIBezierPath?

我想塑造一个UIView并能够在界面生成器中看到它的形状,当我将以下类设置为我的UIView它无法构建,我不确定错误在哪里。

@IBDesignable
class CircleExampleView: UIView {

    override func layoutSubviews() {
        setupMask()
    }

    func setupMask() {

        let path = makePath()

        // mask the whole view to that shape
        let mask = CAShapeLayer()
        mask.path = path.cgPath
        self.layer.mask = mask
    }

    private func makePath() -> UIBezierPath {

        //// Oval Drawing
        let ovalPath = UIBezierPath(ovalIn: CGRect(x: 11, y: 12, width: 30, height: 30))
        UIColor.gray.setFill()
        ovalPath.fill()

        return ovalPath
    }
}

几个观察:

  1. 您正在调用setFill后跟fill ,但只有在绘制到图形上下文中时才这样做(例如,在draw(_:) )。 使用CAShapeLayer ,您应该设置CAShapeLayerfillColor

  2. 您正在使用CAShapeLayer来设置视图的遮罩。 如果您的UIView没有可辨别的backgroundColor ,您将看不到任何内容。

    如果您将视图的背景颜色设置为蓝色,如下所示,您的蒙版将在蒙版允许的任何地方(在路径的椭圆中)显示蓝色背景。

  3. 您已经实现了layoutSubviews 通常只有当你在这里做一些取决于视图bounds的事情时,你才会这样做。 例如,这里的椭圆路径基于视图的bounds的再现:

     @IBDesignable class CircleView: UIView { override func layoutSubviews() { super.layoutSubviews() setupMask() } private func setupMask() { let mask = CAShapeLayer() mask.path = path.cgPath mask.fillColor = UIColor.gray.cgColor layer.mask = mask } private var path: UIBezierPath { return UIBezierPath(ovalIn: bounds) } }
  4. 正如 E. Coms 所说,如果你覆盖layoutSubviews ,你真的应该调用super实现。 这并不重要,因为默认实现实际上什么都不做,但这是最佳实践。 例如,如果您稍后将此类更改为其他UIView子类的子类,则您不需要重新访问所有这些覆盖。

  5. 如果您有可设计的视图,建议将其放在单独的目标中。 这样,故事板中视图的渲染不依赖于主项目中可能正在进行的任何工作。 只要可设计目标(通常是带有Kit后缀的主要目标的名称)可以构建,就可以渲染可设计视图。

例如,这里是您的可设计视图的再现,在单独的框架目标中,并在故事板中使用,其中所讨论的视图具有蓝色backgroundColor

在此处输入图片说明


就其价值而言,我认为必须屏蔽以显示椭圆内的背景颜色非常令人困惑。 应用程序开发人员必须设置“背景”颜色才能设置椭圆内的内容,而不是背景。

我可能会删除“掩码”逻辑,而是为可设计视图提供一个可检查的属性fillColor ,然后使用该fillColor添加一个CAShapeLayer作为子图层:

@IBDesignable
class CircleView: UIView {

    private var shapeLayer = CAShapeLayer()

    @IBInspectable var fillColor: UIColor = .blue {
        didSet {
            shapeLayer.fillColor = fillColor.cgColor
        }
    }

    override init(frame: CGRect = .zero) {
        super.init(frame: frame)

        configure()
    }

    required init?(coder aDecoder: NSCoder) {
        super.init(coder: aDecoder)

        configure()
    }

    private func configure() {
        shapeLayer.fillColor = fillColor.cgColor
        layer.addSublayer(shapeLayer)
    }

    override func layoutSubviews() {
        super.layoutSubviews()

        shapeLayer.path = UIBezierPath(ovalIn: bounds).cgPath
    }
}

这完成了同样的事情,但我认为填充颜色与背景颜色的区别更直观。 但是您可能有其他原因使用遮罩方法,但只要确保如果您这样做,在遮罩后您有一些东西要显示(例如背景颜色或您正在渲染的其他东西)。

请添加“super.layoutSubviews()”

override func layoutSubviews() {
    setupMask()
    super.layoutSubviews()
}

通过这种方式,您的设计视图将是“最新的”。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM