UIView bounds.applying, но с вращением - PullRequest
0 голосов
/ 01 октября 2018

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

Вот мой код:

func addBorder() {        
    let f = selectedObject.bounds.applying(selectedObject.transform)
    borderView.backgroundColor = UIColor(red: 1, green: 0, blue: 0, alpha: 0.5) //just for testing
    borderView.frame = f
    borderView.center = selectedObject.center
    borderView.transform = CGAffineTransform(translationX: selectedObject.transform.tx, y: selectedObject.transform.ty)

    removeBorder() //remove old border

    let f2 = CGRect(x: 0, y: 0, width: borderView.frame.width, height: borderView.frame.height)
    let dashedBorder = CAShapeLayer()
    dashedBorder.strokeColor = UIColor.black.cgColor
    dashedBorder.lineDashPattern = [2, 2]
    dashedBorder.frame = f2
    dashedBorder.fillColor = nil
    dashedBorder.path = UIBezierPath(rect: f2).cgPath
    dashedBorder.name = "border"
    borderView.layer.addSublayer(dashedBorder)
}

И это выглядит так: enter image description here

Это не плохо, но я хочу, чтобы границаповернуть также, потому что это может вводить в заблуждение пользователя, поскольку область касания находится только на изображении.

Я пытался применить вращение к преобразованию:

func addBorder() {        
    let f = selectedObject.bounds.applying(selectedObject.transform)
    borderView.backgroundColor = UIColor(red: 1, green: 0, blue: 0, alpha: 0.5) //just for testing
    borderView.frame = f
    borderView.center = selectedObject.center
    let rotation = atan2(selectedObject.transform.b, selectedObject.transform.a)

    borderView.transform = CGAffineTransform(rotationAngle: rotation).translatedBy(x: selectedObject.transform.tx, y: selectedObject.transform.ty)

    removeBorder() //remove old border

    let f2 = CGRect(x: 0, y: 0, width: borderView.frame.width, height: borderView.frame.height)
    let dashedBorder = CAShapeLayer()
    dashedBorder.strokeColor = UIColor.black.cgColor
    dashedBorder.lineDashPattern = [2, 2]
    dashedBorder.frame = f2
    dashedBorder.fillColor = nil
    dashedBorder.path = UIBezierPath(rect: f2).cgPath
    dashedBorder.name = "border"
    borderView.layer.addSublayer(dashedBorder)
}

Но послевращение выглядит так:

enter image description here

Как это исправить?

Ответы [ 3 ]

0 голосов
/ 10 октября 2018

Вот решение проблемы:

func addBorder() {

    borderView.backgroundColor = UIColor(red: 1, green: 0, blue: 0, alpha: 0.5) //just for testing
    let degrees: CGFloat = 20.0 //the value in degrees for rotation
    let radians: CGFloat = degrees * (.pi / 180)
    borderView.transform = CGAffineTransform(rotationAngle: radians)

    removeBorder()

    let dashedBorder = CAShapeLayer()
    dashedBorder.strokeColor = UIColor.black.cgColor
    dashedBorder.lineDashPattern = [2, 2]
    dashedBorder.frame = borderView.bounds
    dashedBorder.fillColor = nil
    dashedBorder.path = UIBezierPath(roundedRect: borderView.bounds, cornerRadius:0).cgPath
    dashedBorder.name = "border"
    borderView.layer.addSublayer(dashedBorder)
}

Приведенный выше код протестирован в Xcode 10 с Swift 4.2

0 голосов
/ 11 октября 2018

Несмотря на то, что я принял ответ, потому что это помогло мне понять проблему, я публикую окончательный ответ, потому что это больше к нему.И я думаю, что это может быть полезно для кого-то еще, потому что я не мог найти это решение в Stackoverflow или где-то еще.

Идея состоит в том, чтобы создать borderView с границами, такими же, как selectedObject.Это было решением @Incredible_dev, однако была одна проблема: сама линия растягивается, когда borderView масштабируется в любом направлении.И я хочу сохранить размер строки и просто она должна быть около selectedObject.Итак, я умножаю selectedObject границы с масштабом, извлеченным из selectedObject.transform.Затем я копирую перевод и ротацию из selectedObject.

Вот окончательный код:

var borderView: UIView!
var selectedObject: UIView?

extension CGAffineTransform { //helper extension

    func getScale() -> CGFloat {
        return (self.a * self.a + self.c * self.c).squareRoot()
    }

    func getRotation() -> CGFloat {
        return atan2(self.b, self.a)
    }

}

func removeBorder() { //remove the older border
    if borderView != nil {
        borderView.removeFromSuperview()
    }
}

func addBorder() {
    guard let selectedObject = selectedObject else { return }

    removeBorder() //remove old border

    let t = selectedObject.transform
    let s = t.getScale()
    let r = t.getRotation()

    borderView = UIView(frame: CGRect(x: 0, y: 0, width: selectedObject.bounds.width * s, height: selectedObject.bounds.height * s)) //multiply bounds with selectedObject's scale
    dividerImageView.addSubview(borderView) //add borderView to the "scene"

    borderView.transform = CGAffineTransform(translationX: t.tx, y: t.ty).rotated(by: r) //copy translation and rotation, order is important
    borderView.center = selectedObject.center

    let dashedBorder = CAShapeLayer() //create 2-point wide dashed line
    dashedBorder.lineWidth = 2
    dashedBorder.strokeColor = UIColor.black.cgColor
    dashedBorder.lineDashPattern = [2, 2]
    dashedBorder.fillColor = nil
    dashedBorder.path = UIBezierPath(rect: borderView.bounds).cgPath
    borderView.layer.addSublayer(dashedBorder)
}
0 голосов
/ 01 октября 2018

Вот пример, основанный на вашем коде:

//initial transforms
selectedObject.transform = CGAffineTransform.init(rotationAngle: .pi / 4).translatedBy(x: 150, y: 15)

func addBorder() {
    let borderView = UIView.init(frame: selectedObject.bounds)
    self.view.addSubview(borderView)
    borderView.backgroundColor = UIColor(red: 1, green: 0, blue: 0, alpha: 0.5) //just for testing
    borderView.center = selectedObject.center
    borderView.transform = selectedObject.transform

    removeBorder() //remove old border

    let dashedBorder = CAShapeLayer()
    dashedBorder.strokeColor = UIColor.black.cgColor
    dashedBorder.lineDashPattern = [2, 2]
    dashedBorder.fillColor = nil
    dashedBorder.path = UIBezierPath(rect: borderView.bounds).cgPath
    dashedBorder.name = "border"
    borderView.layer.addSublayer(dashedBorder)
}
...