Выровненные линии Da sh Patterns в 2 CAShapeLayer - PullRequest
0 голосов
/ 08 марта 2020

Я призываю вас, боги основной анимации! Я пытаюсь отобразить форму в iOS. Идея состоит в том, чтобы нарисовать квадрат с пунктирными штрихами, внутренним и внешним, как показано на следующем рисунке, созданном с помощью приложения Sketch.

square shape with two dashed borders created in sketch

I ' m реализуя его, создавая три слоя, один для внешнего хода, один для внутреннего и один для заливки. Вот мой код:

        // setup square properties
        let lineDashPattern = [10, 5]
            .map({ NSNumber(value: $0) })
        let strokeWidth = CGFloat(5)
        let frame = CGRect(
            x: 40,
            y: 40,
            width: 119,
            height: 119)
        let pathBox = CGRect(
            x: 0,
            y: 0,
            width: frame.size.width,
            height: frame.size.width)

        // Create the container layer
        let square = CALayer()
        square.frame = frame

        // create the fill
        let fill = CAShapeLayer()
        fill.frame = pathBox
        fill.fillColor = UIColor.lightGray.cgColor
        fill.path = UIBezierPath(rect: frame).cgPath

        // Creater the inner border
        let innerBorder = CAShapeLayer()
        innerBorder.frame = frame
        innerBorder.lineWidth = strokeWidth
        innerBorder.strokeColor = UIColor.blue.cgColor
        innerBorder.lineDashPattern = lineDashPattern
        innerBorder.fillColor = UIColor.clear.cgColor
        innerBorder.path = UIBezierPath(rect: pathBox)
            .cgPath
            .contract(by: strokeWidth / 2)

        // Create the outer border
        let outerBorder = CAShapeLayer()
        outerBorder.frame = frame
        outerBorder.lineWidth = strokeWidth
        outerBorder.strokeColor = UIColor.red.cgColor
        outerBorder.lineDashPattern = lineDashPattern
        outerBorder.fillColor = UIColor.clear.cgColor
        outerBorder.path = UIBezierPath(rect: pathBox)
            .cgPath
            .contract(by: -(strokeWidth / 2))

        // add all to screen
        square.addSublayer(fill)
        square.addSublayer(innerBorder)
        square.addSublayer(outerBorder)
        view.layer.addSublayer(square)

Я также создал следующие расширения в CGPath, чтобы облегчить масштабирование пути фигуры для создания штрихов:

extension CGPath {
    func contract(by value: CGFloat) -> CGPath {
        let finalBoundingBox = boundingBox.insetBy(
            dx: value,
            dy: value)
        let scaleFactor: CGFloat = finalBoundingBox.width / boundingBox.width

        var scaleTransform = CGAffineTransform.identity
            .centerScaledBy(x: scaleFactor, y: scaleFactor, bounds: boundingBox)

        return copy(using: &scaleTransform)!
    }

}

extension CGAffineTransform {

    func centerScaledBy(x:CGFloat, y:CGFloat, bounds: CGRect) -> CGAffineTransform {
        let center = bounds.center
        var xform  = self

        xform = xform.concatenating(CGAffineTransform(translationX: -center.x, y: -center.y))
        xform = xform.concatenating(CGAffineTransform(scaleX: x, y: y))
        xform = xform.concatenating(CGAffineTransform(translationX: center.x, y: center.y))

        return xform
    }
}

extension CGRect {

    var center: CGPoint {
        return CGPoint(x: self.midX, y: midY)
    }
}

Однако результат будет другим , Я получаю полностью смещенные штрихи штрихов, такие как:

square shape with two dashed borders created in with core animation

Я предполагаю, что Sketch использует слои Core Animation под капотом, поэтому все, что можно сделать с помощью эскиза, должно также воспроизводим по коду, верно?

Заранее спасибо.

1 Ответ

0 голосов
/ 23 марта 2020

Черточки в примере приложения Sketch не похожи на обычные черточки - обратите внимание, что длины сегментов da sh в углах неоднородны. Чтобы воссоздать это, я бы просто использовал восемь отдельных слоев: четыре для четырех внутренних краев, а затем еще четыре слоя для внешних краев. Я бы поиграл с lineDashPhase , чтобы шаблоны da sh на внешних краях соответствовали внутренним.

...