Почему эти CAShapeLayers не идут туда, где ожидается? - PullRequest
0 голосов
/ 09 мая 2019

Я работаю над пользовательским индикатором загрузки и у меня много проблем с CAShapeLayers.

Индикатор загрузки будет содержаться в пользовательском UIView, чтобы его мог использовать любой viewController.

Первый выпуск:

Рамка подпредставления не соответствует границам.

При использовании этого кода для отображения круга в каждом углу рамки круги помещаются в квадратную форму, но их нет рядом с видом. импорт UIKit

Контроллер просмотра:

class MergingCicles: UIViewController, HolderViewDelegate {
func animateLabel() {

}

var holderView = HolderView(frame: CGRect.zero)

override func viewDidLoad() {
    super.viewDidLoad()
}

override func viewDidAppear(_ animated: Bool) {
    super.viewDidAppear(animated)
    addHolderView()
}

override func didReceiveMemoryWarning() {
    super.didReceiveMemoryWarning()
}

func addHolderView() {
    let boxSize: CGFloat = 100.0
    holderView.frame = CGRect(x: view.bounds.width / 2 - boxSize / 2,
                              y: view.bounds.height / 2 - boxSize / 2,
                              width: boxSize,
                              height: boxSize)
    holderView.parentFrame = view.frame
    holderView.delegate = self
    holderView.center = self.view.center
    view.addSubview(holderView)
    holderView.addCircleLayer()
}
}

подвид:

Import UIKit

protocol HolderViewDelegate:class {
func animateLabel()
}

class HolderView: UIView {
let initalLayer = InitialLayer()
let triangleLayer = TriangleLayer()
let redRectangleLayer = RectangleLayer()
let blueRectangleLayer = RectangleLayer()
let arcLayer = ArcLayer()

var parentFrame :CGRect = CGRect.zero
weak var delegate:HolderViewDelegate?

override init(frame: CGRect) {
    super.init(frame: frame)
    backgroundColor = UIColor.clear
}

required init(coder: NSCoder) {
    super.init(coder: coder)!
}

func addCircleLayer() {
    var circleLocations = [CGPoint]()
    let offset = CircleLayer().maxSize / 2
    circleLocations.append(CGPoint(x: self.frame.maxX - offset, y: self.frame.maxY - offset))
    circleLocations.append(CGPoint(x: self.frame.minX + offset, y: self.frame.minY + offset))
    circleLocations.append(CGPoint(x: self.frame.maxX - offset, y: self.frame.minY + offset))
    circleLocations.append(CGPoint(x: self.frame.minX + offset, y: self.frame.maxY - offset))
    circleLocations.append(layer.anchorPoint)
    for point in circleLocations {
        let circle = CircleLayer()
        circle.updateLocation(Size: .medium, center: point)
            self.layer.addSublayer(circle)

    }
    self.backgroundColor = .blue
   // layer.anchorPoint = CGPoint(x: (self.bounds.maxX + self.bounds.maxX)/2, y: (self.bounds.maxY + self.bounds.minY)/2)
    let rotationAnimation: CABasicAnimation = CABasicAnimation(keyPath: "transform.rotation.z")
    rotationAnimation.toValue = CGFloat(Double.pi * 2)
    rotationAnimation.duration = 0.45
    rotationAnimation.isCumulative = true
    //rotationAnimation.repeatCount = 1000
    //rotationAnimation.isRemovedOnCompletion = true
  //  layer.add(rotationAnimation, forKey: nil)
}

}

Круговой слой:

import Foundation
import UIKit

enum ShapeSize {
    case medium
    case small
    case large
}
class CircleLayer: CAShapeLayer {
let animationDuration: CFTimeInterval = 0.3
let maxSize = CGFloat(50)
override init() {
    super.init()
    fillColor = UIColor.red.cgColor
}

func updateLocation(Size: ShapeSize, center: CGPoint){
    switch Size {
    case .medium:
        path = UIBezierPath(ovalIn: CGRect(x: center.x, y: center.y, width: maxSize/3, height: maxSize/3)).cgPath
    case .small:
        path = UIBezierPath(ovalIn: CGRect(x: center.x, y: center.y, width: (2*maxSize)/3, height: (2*maxSize)/3)).cgPath
    case .large:
        path = UIBezierPath(ovalIn: CGRect(x: center.x, y: center.y, width: maxSize, height: maxSize)).cgPath
    }
}

required init(coder aDecoder: NSCoder) {
    fatalError("init(coder:) has not been implemented")
}
}

Результат:

Result using frame

Это действительно показывает, что кадр находится рядом с uiView.

Если я изменю addCircleLayer на использование границ, я получу нечто гораздо ближе:

Using bounds

Но все же круги не в углах (кроме нижнего правого, это правильно). Похоже, что слева и вверху есть дополнительное пространство, которое не захватывается с помощью self.bounds.

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

Ответы [ 2 ]

1 голос
/ 09 мая 2019

Ты говоришь такие вещи, как

circleLocations.append(CGPoint(x: self.frame.maxX - offset, y: self.frame.maxY - offset))

Но self.frame - это место, где вид находится в своем собственном суперпредставлении. Таким образом, слой формы заканчивается смещением от вида настолько, насколько вид смещается от своего собственного суперпредставления. Где бы вы ни говорили frame здесь, вы имеете в виду bounds.

0 голосов
/ 09 мая 2019

Я обнаружил, что проблема была тогда, когда я рисовал круги, которые я использовал UIBezierPath(ovalIn:CGRect, width: CGFloat, height: CGFloat, который использовал значение x для левой стороны круга.Когда я изменил значение на UIBezierPath(arcCenter: CGPoint, radius: CGFloat, startAngle: CGFloat, endAngle: CGFloat, clockwise: Bool), точка использовалась для центра круга, и при расчете точек использовала все, что ожидалось, при использовании self.bounds.

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

Я не понял, почему кадр находится в совершенно другом месте, но он больше не влияет на проект.

...