Как я могу добавить UIBezierPath в UIView, который использует автоматический макет? - PullRequest
0 голосов
/ 06 мая 2020

В моем проекте я хочу добавить строку в UIView (этот UIView использует автоматический макет). Я использую UIBezierPath и CAShapeLayer, чтобы нарисовать линию.

Это мой код:

let myView = UIView()
self.view.addSubView(myView)
myView.translatesAutoresizingMaskIntoConstraints = false
myView.topAnchor.constraint(equalTo: self.view.topAnchor).isActive = true
myView.heightAnchor.constraint(equalToConstant: 40).isActive = true
myView.widthAnchor.constraint(equalToConstant: 100).isActive = true
myView.rightAnchor.constraint(equalTo: self.view.rightAnchor).isActive = true

let path = UIBezierPath()
path.move(to: CGPoint(x: 0, y: myView.frame.height/2))
path.addLine(to: CGPoint(x: myView.frame.width, y: myView.frame.height/2))

let shapeLayer = CAShapeLayer()
shapeLayer.path = path.cgPath
shapeLayer.strokeColor = UIColor.black.cgColor
shapeLayer.lineWidth = 11.0

myView.layer.addSublayer(shapeLayer)

Но моя проблема в том, что в viewController нет строки. Когда я использую этот код, все в порядке, и строка отлично показывает:

let myView = UIView(frame: CGRect(x: 0, y: 160, width: 100, height: 40))
self.view.addSubView(myView)

Как я могу решить эту проблему? Я должен использовать автоматический макет.

Ответы [ 2 ]

1 голос
/ 06 мая 2020

Лучше всего использовать собственный подкласс UIView и установить путь к слою в layoutSubviews(). Таким образом, вы получите нужный кадр, когда это необходимо.

Вот простой пример:

class LineView: UIView {

    let shapeLayer: CAShapeLayer = CAShapeLayer()

    override init(frame: CGRect) {
        super.init(frame: frame)
        commonInit()
    }

    required init?(coder: NSCoder) {
        super.init(coder: coder)
        commonInit()
    }

    func commonInit() -> Void {

        layer.addSublayer(shapeLayer)
        shapeLayer.strokeColor = UIColor.black.cgColor
        shapeLayer.lineWidth = 11.0

    }

    override func layoutSubviews() {
        super.layoutSubviews()

        let path = UIBezierPath()
        path.move(to: CGPoint(x: 0, y: bounds.midY))
        path.addLine(to: CGPoint(x: bounds.maxX, y: bounds.midY))

        shapeLayer.path = path.cgPath

    }
}

class ViewController: UIViewController {

    override func viewDidLoad() {
        super.viewDidLoad()

        let myView = LineView()
        myView.translatesAutoresizingMaskIntoConstraints = false
        view.addSubview(myView)
        NSLayoutConstraint.activate([
            myView.topAnchor.constraint(equalTo: self.view.topAnchor),
            myView.heightAnchor.constraint(equalToConstant: 40),
            myView.widthAnchor.constraint(equalToConstant: 100),
            myView.rightAnchor.constraint(equalTo: self.view.rightAnchor),
        ])

        // if you want to see the frame of myView
        //myView.backgroundColor = .yellow

    }

}

Результат - с желтым фоном, чтобы мы могли видеть кадр, и с вашими ограничениями (вы, вероятно, захотите использовать safeArea ...):

enter image description here

0 голосов
/ 06 мая 2020

Думаю, я нашел вашу проблему. Вы определили UIView с фреймом (0, 0, 0, 0). Если вы затем нарисуете линию в этом виде с координатами этой линии, связанной с этим видом, вы не получите линии.

Я предполагаю, что вы хотите, чтобы ваше представление было на 0, 160 с высотой 40 и ширина 100. Затем линия должна проходить от (0, 20) до (100, 20).

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

Я сделал следующий код, который может помочь. Вы устанавливаете свои ограничения так, как вам нравится.

Создайте собственное представление (MyLineView) следующим образом:

import UIKit

class MyLineView: UIView {

    private let lineColor = UIColor.black

    override func draw(_ rect: CGRect) {

        let path = UIBezierPath()
        lineColor.setStroke()
        path.lineWidth = 11

        path.move(to: CGPoint(x: self.frame.origin.x, y: self.frame.size.height / 2))
        path.addLine(to: CGPoint(x: self.frame.size.width, y: self.frame.size.height / 2))
        path.stroke()

        print(self.frame)
    }
}

Затем вы можете закодировать свой контроллер представления следующим образом:

import UIKit

class ViewController: UIViewController {

    override func viewDidLoad() {
        super.viewDidLoad()

//        let myView = UIView(frame: CGRect(x: 0, y: 160, width: 100, height: 40))
        let myView = MyLineView()

        let viewPositionX: CGFloat = 0
        let viewPositionY: CGFloat = 160
        let viewWidth: CGFloat = 100
        let viewHeight: CGFloat = 40

        let topConstraint = viewPositionY + viewHeight - self.view.frame.size.height
        let widthConstraint = viewWidth - self.view.frame.size.width

        myView.backgroundColor = UIColor.green

        self.view.addSubview(myView)
        myView.translatesAutoresizingMaskIntoConstraints = false
        NSLayoutConstraint(item: myView, attribute: .leading, relatedBy: .equal, toItem: self.view, attribute: .leading, multiplier: 1, constant: viewPositionX).isActive = true
        NSLayoutConstraint(item: myView, attribute: .top, relatedBy: .equal, toItem: self.view, attribute: .top, multiplier: 1, constant: viewPositionY).isActive = true
        NSLayoutConstraint(item: myView, attribute: .bottom, relatedBy: .equal, toItem: self.view, attribute: .bottom, multiplier: 1, constant: topConstraint).isActive = true
        NSLayoutConstraint(item: myView, attribute: .trailing, relatedBy: .equal, toItem: self.view, attribute: .trailing, multiplier: 1, constant: widthConstraint).isActive = true
    }
}

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...