Могут ли фигуры CAShapeLayer центрироваться в подпредставлении?

Я создал произвольное представление

let middleView = UIView(
    frame: CGRect(x: 0.0,
                  y: view.frame.height/4,
                  width: view.frame.width,
                  height: view.frame.height/4))
middleView.backgroundColor = UIColor.blue
view.addSubview(middleView)

Затем я создал круг, используя UIBezierPath; однако, когда я устанавливаю положение middleView.center, круг находится далеко от нижней части представления. Можете ли вы установить положение в центре подвида?

iPhone 8 Plus с обзором и кругом без центра

let shapeLayer = CAShapeLayer()
let circlePath = UIBezierPath(
        arcCenter: .zero,
        radius: 100,
        startAngle: CGFloat(0).toRadians(),
        endAngle: CGFloat(360).toRadians(),
        clockwise: true)
shapeLayer.path = circlePath.cgPath
shapeLayer.strokeColor = UIColor.purple.cgColor
shapeLayer.fillColor = UIColor.clear.cgColor
shapeLayer.position = middleView.center
middleView.layer.addSublayer(shapeLayer)

Как мне центрировать этот круг в этом представлении?


person theptrk    schedule 08.09.2018    source источник


Ответы (1)


У вас есть две проблемы.

Во-первых, вы устанавливаете shapeLayer.position = middleView.center. center представления - это геометрия суперпредставления. Другими словами, middleView.center относится к view, а не к middleView. Но затем вы добавляете shapeLayer в качестве подслоя middleView.layer, что означает, что shapeLayer нужен position, который находится в геометрии middleView, а не в геометрии view. Вам нужно установить shapeLayer.position в центр middleView.bounds:

shapeLayer.position = CGPoint(x: middleView.bounds.midX, y: middleView.bounds.midY)

Во-вторых, вы не сказали, где вы все это делаете. Я предполагаю, что вы делаете это в viewDidLoad. Но это слишком рано. В viewDidLoad представления, загруженные из раскадровки, по-прежнему имеют кадры, которые им были даны в раскадровке, и еще не были выложены для текущего размера экрана устройства. Поэтому не стоит смотреть на frame (или bounds, или center) в viewDidLoad, если вы не сделаете что-то, чтобы убедиться, что все будет правильно размещено на этапе макета. Обычно вы делаете это, устанавливая autoresizingMask или создавая ограничения. Пример:

let middleView = UIView(
    frame: CGRect(x: 0.0,
                  y: view.frame.height/4,
                  width: view.frame.width,
                  height: view.frame.height/4))
middleView.backgroundColor = UIColor.blue
middleView.autoresizingMask = [.flexibleWidth, .flexibleHeight, .flexibleTopMargin, .flexibleBottomMargin]
view.addSubview(middleView)

Однако shapeLayer не принадлежит представлению, поэтому оно не имеет autoresizingMask и не может быть ограничено. Вы должны изложить это в коде. Вы можете сделать это, но лучше просто использовать представление для управления слоем формы. Таким образом, вы можете использовать autoresizingMask или ограничения для управления макетом фигуры, и вы можете настроить его в viewDidLoad.

    let circleView = CircleView(frame: CGRect(x: 0, y: 0, width: 200, height: 200))
    circleView.center = CGPoint(x: middleView.bounds.midX, y: middleView.bounds.midY)
    circleView.autoresizingMask = [.flexibleLeftMargin, .flexibleRightMargin, .flexibleTopMargin, .flexibleBottomMargin]
    circleView.shapeLayer.strokeColor = UIColor.purple.cgColor
    circleView.shapeLayer.fillColor = nil
    middleView.addSubview(circleView)

...

class CircleView: UIView {
    override class var layerClass: AnyClass { return CAShapeLayer.self }

    var shapeLayer: CAShapeLayer { return layer as! CAShapeLayer }

    override func layoutSubviews() {
        super.layoutSubviews()
        shapeLayer.path = UIBezierPath(ovalIn: bounds).cgPath
    }

}

Результат:

демонстрация

И после поворота в альбомную:

демонстрация в альбомной ориентации

person rob mayoff    schedule 08.09.2018
comment
Благодарность! это было очень познавательно. Один вопрос: можно ли отключить circleView.autoresizingMask = [...] для ограничений автомакета? они выполняют одну и ту же задачу? - person theptrk; 08.09.2018
comment
Да, вы можете использовать ограничения для размещения circleView, если не забудете установить circleVIew.translatesAutoresizingMaskIntoConstraints = false. - person rob mayoff; 08.09.2018
comment
Я думаю, я запутался, как 0 в CGRect.x и CGRect.y позволяет центрировать круг - person theptrk; 08.09.2018
comment
Это не имеет значения, потому что я установил circleView.center на следующей строке. - person rob mayoff; 08.09.2018