2 votes

La création d'une vue avec des contraintes programmatiques entraîne l'affichage du contenu au mauvais endroit.

J'ajoute une vue personnalisée à une autre vue dont les contraintes sont définies par programme. Il en résulte que le contenu de la vue est dessiné au mauvais endroit, et je ne sais pas exactement pourquoi. Voici le code que j'ai et ce que j'ai essayé jusqu'à présent : enter image description here

// Called in viewDidLoad
let buttonView = UIView()
buttonView.translatesAutoresizingMaskIntoConstraints = false

let ring = CircularProgressView()
ring.frame = CGRect(x: 0, y: 0, width: 80, height: 80)  
ring.backgroundColor = .yellow

buttonView.addSubview(ring)
self.view.addSubview(buttonView)

NSLayoutConstraint.activate([
    buttonView.bottomAnchor.constraint(equalTo: view.safeAreaLayoutGuide.bottomAnchor, constant: -12),
    buttonView.trailingAnchor.constraint(equalTo: view.safeAreaLayoutGuide.trailingAnchor, constant: -28),
    buttonView.heightAnchor.constraint(equalToConstant: 80),
    buttonView.widthAnchor.constraint(equalToConstant: 80),

    ring.centerXAnchor.constraint(equalTo: buttonView.centerXAnchor),
    ring.centerYAnchor.constraint(equalTo: buttonView.centerYAnchor)
])

J'ai essayé d'appeler ring.layoutIfNeeded() ou de définir la largeur et la hauteur de la vue de l'anneau avec des contraintes, mais cela n'a rien changé.

ring.heightAnchor.constraint(equalToConstant: 80),
ring.widthAnchor.constraint(equalToConstant: 80)

La classe CircularProgressView se présente comme suit. J'ai essayé d'utiliser bounds au lieu de frame ou de ne pas diviser les valeurs par 2, mais là encore, rien ne change.

class CircularProgressView: UIView {

    // First create two layer properties
    private var circleLayer = CAShapeLayer()
    private var progressLayer = CAShapeLayer()
    private var currentValue: Double = 0

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

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

    func createCircularPath() {
        let circularPath = UIBezierPath(arcCenter: CGPoint(x: frame.size.width / 2.0, y: frame.size.height / 2.0),
                                        radius: 41,
                                        startAngle: -.pi / 2,
                                        endAngle: 3 * .pi / 2,
                                        clockwise: true)
        circleLayer.path = circularPath.cgPath
        circleLayer.fillColor = UIColor.clear.cgColor
        circleLayer.lineCap = .round
        circleLayer.lineWidth = 3.0
        circleLayer.strokeColor = UIColor.black.withAlphaComponent(0.2).cgColor
        progressLayer.path = circularPath.cgPath
        progressLayer.fillColor = UIColor.clear.cgColor
        progressLayer.lineCap = .round
        progressLayer.lineWidth = 3.0
        progressLayer.strokeEnd = 0
        progressLayer.strokeColor = UIColor.black.cgColor

        layer.addSublayer(circleLayer)
        layer.addSublayer(progressLayer)

        let circularProgressAnimation = CABasicAnimation(keyPath: "strokeEnd")
        circularProgressAnimation.duration = 2
        circularProgressAnimation.toValue = 1
        circularProgressAnimation.fillMode = .forwards
        circularProgressAnimation.isRemovedOnCompletion = false
        progressLayer.add(circularProgressAnimation, forKey: "progressAnim")
        progressLayer.pauseAnimation()
    }
}

Tout cela fonctionne sans problème si l'on utilise le storyboard, mais j'ai besoin de le créer par programme pour ce cas d'utilisation, et je ne comprends pas très bien ce qui ne va pas.

2voto

Sh_Khan Points 45592

Vous devez créer les deux vues par programme, comme suit

// Called in viewDidLoad
let buttonView = UIView()
buttonView.translatesAutoresizingMaskIntoConstraints = false

let ring = CircularProgressView()
ring.translatesAutoresizingMaskIntoConstraints = false 
ring.backgroundColor = .yellow

buttonView.addSubview(ring)
self.view.addSubview(buttonView)

NSLayoutConstraint.activate([
    buttonView.bottomAnchor.constraint(equalTo: view.safeAreaLayoutGuide.bottomAnchor, constant: -12),
    buttonView.trailingAnchor.constraint(equalTo: view.safeAreaLayoutGuide.trailingAnchor, constant: -28),
    buttonView.heightAnchor.constraint(equalToConstant: 80),
    buttonView.widthAnchor.constraint(equalToConstant: 80),

    ring.centerXAnchor.constraint(equalTo: buttonView.centerXAnchor),
    ring.centerYAnchor.constraint(equalTo: buttonView.centerYAnchor),
    ring.heightAnchor.constraint(equalToConstant: 80),
    ring.widthAnchor.constraint(equalToConstant: 80)
])

et Appel createCircularPath uniquement à l'intérieur layoutSubviews

override func layoutSubviews() {
   super.layoutSubviews()
   createCircularPath()
}

1voto

gcharita Points 474

Essayez également de définir CircularProgressView 's translatesAutoresizingMaskIntoConstraints à la propriété false :

ring.translatesAutoresizingMaskIntoConstraints = false

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X