Tengo un cliente que solicitó lo siguiente en su diseño:

¿Cuál es la forma más fácil de crear el recipiente amarillo, con el borde inclinado en la parte inferior? ¿Puedo hacerlo dentro del constructor de interfaces o tengo que hacerlo programáticamente? Estoy tratando de hacer esto rápidamente.

1
sushibrain 14 nov. 2017 a las 21:19

2 respuestas

La mejor respuesta

¿Puedo hacerlo dentro del generador de interfaces o tengo que hacerlo mediante programación?

Tendrá que hacer esto programáticamente: Defina el UIBezierPath, utilizándolo como el path de un CAShapeLayer y luego enmascare la capa de la vista usando esta capa de forma.

@IBDesignable
class SlantedView: UIView {

    @IBInspectable var slantHeight: CGFloat = 50 { didSet { updatePath() } }

    private let shapeLayer: CAShapeLayer = {
        let shapeLayer = CAShapeLayer()
        shapeLayer.lineWidth = 0
        shapeLayer.fillColor = UIColor.white.cgColor    // with masks, the color of the shape layer doesn’t matter; it only uses the alpha channel; the color of the view is dictate by its background color
        return shapeLayer
    }()

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

    private func updatePath() {
        let path = UIBezierPath()
        path.move(to: bounds.origin)
        path.addLine(to: CGPoint(x: bounds.maxX, y: bounds.minY))
        path.addLine(to: CGPoint(x: bounds.maxX, y: bounds.maxY))
        path.addLine(to: CGPoint(x: bounds.minX, y: bounds.maxY - slantHeight))
        path.close()
        shapeLayer.path = path.cgPath
        layer.mask = shapeLayer
    }
}

Pero al hacer de esta una vista @IBDesignable, puede renderizarla en IB para que al menos pueda diseñar la interfaz de usuario con una mayor idea de cómo se verá el producto final:

enter image description here

Para su información, si lo hace designable, recomiendan que cree un objetivo de marco separado para sus designables (de modo que si va a IB mientras trabaja en su proyecto principal, la capacidad de representar las vistas designables no se ve afectada por el hecho que su proyecto principal puede no estar en un estado estable y compilable).

3
Rob 14 nov. 2017 a las 20:55

¿Quizás crear una vista personalizada que pueda desplegar en el generador de interfaces? Esta versión tiene una propiedad que puede establecer en IB que determina la fracción inclinada para que pueda dimensionarla de la manera que desee:

@IBDesignable class SlantedView: UIView {

    @IBInspectable var slant: Double = 0.8

    override func prepareForInterfaceBuilder() {
        // Called when initialized in IB
        setup()
    }

    override func awakeFromNib() {
        // Called when initialized in actual app
        setup()
    }

    func setup() {
        layer.backgroundColor = UIColor.yellow.cgColor

        recalculateMask()
    }

    func recalculateMask() {
        let shapeLayer = CAShapeLayer()

        let maskPath = CGMutablePath()
        maskPath.move(to: CGPoint(x: 0, y: 0))
        maskPath.addLine(to: CGPoint(x: bounds.width, y: 0))
        maskPath.addLine(to: CGPoint(x: bounds.width, y: bounds.height))
        maskPath.addLine(to: CGPoint(x: 0, y: bounds.height * CGFloat(slant)))

        shapeLayer.path = maskPath
        layer.mask = shapeLayer
    }

    override func layoutSubviews() {
        super.layoutSubviews()
        recalculateMask()
    }
}
0
whistler 14 nov. 2017 a las 19:37