2 votes

Dessin d'une flèche clignotante avec UIBezierPath

J'ai un UIScrollView qui contient un long texte. Je veux informer les utilisateurs qu'il y a plus de contenu à lire. J'ai donc ajouté une flèche avec UIBezierPath sur le fond.

class ArrowView: UIView {
    var arrowPath: UIBezierPath!
    // Only override draw() if you perform custom drawing.
    // An empty implementation adversely affects performance during animation.
    override func draw(_ rect: CGRect) {
        // Drawing code
        self.drawArrow(from: CGPoint(x: rect.midX, y: rect.minY), to: CGPoint(x: rect.midX, y: rect.maxY),
                       tailWidth: 10, headWidth: 25, headLength: 20)

        //arrowPath.fill()
    }

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

        self.backgroundColor = UIColor.darkGray
    }

    required init?(coder aDecoder: NSCoder) {
        super.init(coder: aDecoder)
    }
    private func drawArrow(from start: CGPoint, to end: CGPoint, tailWidth: CGFloat, headWidth: CGFloat, headLength: CGFloat){
        let length = hypot(end.x - start.x, end.y - start.y)
        let tailLength = length - headLength

        func p(_ x: CGFloat, _ y: CGFloat) -> CGPoint { return CGPoint(x: x, y: y) }
        let points: [CGPoint] = [
            p(0, tailWidth / 2),
            p(tailLength, tailWidth / 2),
            p(tailLength, headWidth / 2),
            p(length, 0),
            p(tailLength, -headWidth / 2),
            p(tailLength, -tailWidth / 2),
            p(0, -tailWidth / 2)
        ]

        let cosine = (end.x - start.x) / length
        let sine = (end.y - start.y) / length
        let transform = CGAffineTransform(a: cosine, b: sine, c: -sine, d: cosine, tx: start.x, ty: start.y)

        let path = CGMutablePath()
        path.addLines(between: points, transform: transform)
        path.closeSubpath()

        arrowPath = UIBezierPath.init(cgPath: path)
    }
}

Ma question : Comment puis-je réaliser une animation de clignotement sur une flèche. Supposons qu'elle ait une couche de gradient du blanc au bleu. Il devrait commencer avec le blanc au bleu, puis le bleu devrait être vu sur le point de départ, puis le blanc devrait commencer à être vu sur le point d'arrivée de la flèche et ce cercle devrait continuer.

Au final, cette animation doit informer les utilisateurs qu'ils peuvent faire défiler la vue.

Comment puis-je y parvenir ?

enter image description here

1voto

nikksindia Points 857

Vous pouvez essayer d'utiliser CAGradientLayer avec CAAnimation. Ajoutez un dégradé à votre vue :

override func viewDidAppear(animated: Bool) {

    self.gradient = CAGradientLayer()
    self.gradient?.frame = self.view.bounds
    self.gradient?.colors = [ UIColor.white.cgColor, UIColor.white.cgColor]
    self.view.layer.insertSublayer(self.gradient, atIndex: 0)
    animateLayer()
}

func animateLayer(){

    var fromColors = self.gradient.colors
    var toColors: [AnyObject] = [UIColor.blue.cgColor,UIColor.blue.cgColor]
    self.gradient.colors = toColors
    var animation : CABasicAnimation = CABasicAnimation(keyPath: "colors")

    animation.fromValue = fromColors
    animation.toValue = toColors
    animation.duration = 3.00
    animation.isRemovedOnCompletion = true
    animation.fillMode = CAMediaTimingFillMode.forwards
    animation.timingFunction = CAMediaTimingFunction(name: CAMediaTimingFunctionName.linear)
    animation.delegate = self

    self.gradient?.addAnimation(animation, forKey:"animateGradient")
}

et pour continuer l'animation du gradient dans un ordre cyclique comme :

override func animationDidStop(anim: CAAnimation!, finished flag: Bool) {
    self.toColors = self.fromColors;
    self.fromColors = self.gradient?.colors
    animateLayer()
}

0voto

impression7vx Points 720

Vous pourriez placer votre flèche à l'intérieur d'un objet UIView. Vous pourriez ensuite placer l'UIView sur une minuterie où il changerait l'alpha correctement. En fonction du clignotement ou du fondu, néanmoins, vous pourriez utiliser les animations UIView pour réaliser l'animation souhaitée.

Je dis une uiview, au lieu d'utiliser la scrollview parce que vous ne voulez pas cacher la scrollview. Donc vous le mettez à l'intérieur d'une vue qui n'est qu'un conteneur pour le chemin de bézier.

0voto

Emre Önder Points 863

Je l'ai résolu en utilisant CABasicAnimation() . Ce premier ajout d'une couche de gradient à l'image personnalisée UIView puis appliquer un masque dessus et enfin ajouter une animation.

override func draw(_ rect: CGRect) {
    // Drawing code
    self.drawArrow(from: CGPoint(x: rect.midX, y: rect.minY), to: CGPoint(x: rect.midX, y: rect.maxY),
                   tailWidth: 10, headWidth: 20, headLength: 15)

    //arrowPath.fill()

    let startColor = UIColor(red:0.87, green:0.87, blue:0.87, alpha:1.0).cgColor
    let finishColor = UIColor(red:0.54, green:0.54, blue:0.57, alpha:1.0).withAlphaComponent(0.5).cgColor

    let gradient = CAGradientLayer()
    gradient.frame = self.bounds
    gradient.colors = [startColor,finishColor]

    let shapeMask = CAShapeLayer()
    shapeMask.path = arrowPath.cgPath

    gradient.mask = shapeMask
    let animation = CABasicAnimation(keyPath: "colors")
    animation.fromValue = [startColor, finishColor]
    animation.toValue = [finishColor, startColor]
    animation.duration = 2.0
    animation.autoreverses = true
    animation.repeatCount = Float.infinity

    //add the animation to the gradient
    gradient.add(animation, forKey: nil)

    self.layer.addSublayer(gradient)

}

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