Как нарисовать круг с помощью CAShapeLayer для центрирования в пользовательском UIView программно быстро

Я пытаюсь нарисовать круговой индикатор выполнения с помощью CAShapeLayer внутри пользовательского UIView, который был автоматически ограничен, я не хочу рисовать свой круг в центре моего супер-представления, а скорее в центре моего пользовательского представления, потому что у меня есть другие Представления вверху мой код ниже рисует круг, но он не позиционируется в указанном представлении

// Custom View
let gaugeViewHolder = UIView()
scrollView.addSubview(gaugeViewHolder)
        gaugeViewHolder.translatesAutoresizingMaskIntoConstraints = false
        gaugeViewHolder.backgroundColor = UIColor.black
        gaugeViewHolder.leadingAnchor.constraint(equalTo: motherView.leadingAnchor).isActive = true
        gaugeViewHolder.topAnchor.constraint(equalTo: defaultAccImage.bottomAnchor, constant: 70).isActive = true
        gaugeViewHolder.trailingAnchor.constraint(equalTo: motherView.trailingAnchor).isActive = true
        gaugeViewHolder.heightAnchor.constraint(equalToConstant: 200).isActive = true

//Now my circle
let shapeLayer = CAShapeLayer()
        let centerForGauge = gaugeViewHolder.center

        let circularPath = UIBezierPath(arcCenter: centerForGauge
            , radius: 80, startAngle: 0, endAngle: 2 * CGFloat.pi, clockwise: true)

        shapeLayer.path = circularPath.cgPath
        shapeLayer.strokeColor = UIColor.white.withAlphaComponent(0.20).cgColor
        shapeLayer.lineWidth = 10
        shapeLayer.fillColor = UIColor.clear.cgColor
        shapeLayer.lineCap = kCALineCapRound
        gaugeViewHolder.layer.addSublayer(shapeLayer)

person chevi99    schedule 13.10.2018    source источник
comment
Вы забыли установить рамку своего shapeLayer.   -  person Duncan C    schedule 13.10.2018
comment
@DuncanC, пожалуйста, как мне это сделать, потому что я считаю, что shapeLayer.path = roundPath делает это?   -  person chevi99    schedule 13.10.2018
comment
Нет, путь слоя и его рамка полностью независимы друг от друга. Рамка - это рамка изображения, в которой живет фигура. Путь - это геометрическая фигура, нарисованная в этом поле.   -  person Duncan C    schedule 13.10.2018
comment
Я опубликовал ответ с рабочим кодом, который показывает, как настроить слой-фигуру. Ключевым моментом является то, что вам нужно установить layer.frame = owningView.bounds, а затем, когда вы установите центр вашего пути, он должен быть в системе координат слоя формы (или представления). Свойство center представления находится в системе координат суперпредставления, что не, что вам нужно.   -  person Duncan C    schedule 13.10.2018


Ответы (2)


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

 var gaugeViewHolder : UIView!

     override func viewDidLoad() {
        super.viewDidLoad()
        gaugeViewHolder = UIView()
        scrollView.addSubview(gaugeViewHolder)
        gaugeViewHolder.translatesAutoresizingMaskIntoConstraints = false
        gaugeViewHolder.backgroundColor = UIColor.black
        gaugeViewHolder.leadingAnchor.constraint(equalTo: motherView.leadingAnchor).isActive = true
        gaugeViewHolder.topAnchor.constraint(equalTo: defaultAccImage.bottomAnchor, constant: 70).isActive = true
        gaugeViewHolder.trailingAnchor.constraint(equalTo: motherView.trailingAnchor).isActive = true
        gaugeViewHolder.heightAnchor.constraint(equalToConstant: 200).isActive = true
}


  override func viewDidAppear(_ animated: Bool) {
                super.viewDidAppear(animated)
            let shapeLayer = CAShapeLayer()
            let centerForGauge = gaugeViewHolder.center
            let circularPath = UIBezierPath(arcCenter: centerForGauge
                , radius: 80, startAngle: 0, endAngle: 2 * CGFloat.pi, clockwise: true)

            shapeLayer.path = circularPath.cgPath
            shapeLayer.strokeColor = UIColor.white.withAlphaComponent(0.20).cgColor
            shapeLayer.lineWidth = 10
            shapeLayer.fillColor = UIColor.clear.cgColor
            shapeLayer.lineCap = CAShapeLayerLineCap.round
            gaugeViewHolder.layer.addSublayer(shapeLayer)
        }
person E.Coms    schedule 13.10.2018
comment
@E Coms, ваше решение сработало, но проблема в том, что оно сосредоточено не в середине gaugeViewHolder, а скорее под ним. - person chevi99; 13.10.2018
comment
ваш код был полезен, мне нужно было вычислить ширину моего gaugeViewHolder и разделить на 2, то же самое относится к высоте, а затем назначить их для arcCenter. Спасибо очень полезно. Я скоро отправлю ответ - person chevi99; 13.10.2018
comment
ваш код был полезен мне нужно было вычислить ширину моего gaugeViewHolder и разделить на 2, то же самое применимо к высоте, а затем назначить их для arcCenter. Спасибо очень полезно. Я скоро отправлю ответ - person chevi99; 13.10.2018
comment
Приятно это слышать. - person E.Coms; 13.10.2018

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

Вот код, который добавляет слой формы к представлению, которое я добавил в образец раскадровки приложения и подключил как IBOutlet:

@IBOutlet weak var gaugeViewHolder: UIView!

override func viewWillAppear(_ animated: Bool) {
    super.viewWillAppear(animated)
    gaugeViewHolder.backgroundColor = UIColor.lightGray

    //Now my circle
    let shapeLayer = CAShapeLayer()
    shapeLayer.borderWidth = 2.0 //Add a box on the shape layer so you can see where it gets drawn.

    shapeLayer.frame = gaugeViewHolder.bounds  //Use the view's bounds as the layer's frame

    //Convert gaugeViewHolder's center from it's superview's coordinate system to it's coordinate system
    let centerForGauge = gaugeViewHolder?.superview?.convert(gaugeViewHolder.center, to: gaugeViewHolder) ?? CGPoint.zero

    let lineWidth = CGFloat(5.0)

    //Use 1/2 the shortest side of the shapeLayer's frame for the radius, inset for the circle path's thickness.
    let radius = max(shapeLayer.frame.size.width, shapeLayer.frame.size.height)/2.0 - lineWidth / 2.0

    let circularPath = UIBezierPath(arcCenter: centerForGauge
        , radius: radius, startAngle: 0, endAngle: 2 * CGFloat.pi, clockwise: true)

    shapeLayer.path = circularPath.cgPath
    shapeLayer.strokeColor = UIColor.black.cgColor
    shapeLayer.lineWidth = lineWidth
    shapeLayer.fillColor = UIColor.yellow.cgColor
    shapeLayer.lineCap = .round
    gaugeViewHolder.layer.addSublayer(shapeLayer)
}

Я изменил цвета и альфа-канал и добавил borderWidth к слою с фигурой, чтобы все выделялось.

person Duncan C    schedule 13.10.2018