2
votes

Flèche clignotante dessiner avec UIBezierPath

J'ai un UIScrollView qui contient un long texte. Je souhaite informer les utilisateurs qu'il a plus de contenu à lire. Par conséquent, j'ai ajouté une flèche avec UIBezierPath en bas.

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 clignotante sur la flèche. Supposons qu'il a un calque dégradé du blanc au bleu. Il devrait commencer par du blanc au bleu, puis le bleu devrait être vu au point de départ, puis le blanc devrait commencer à être vu au point d'arrivée de Arrow et ce cercle devrait continuer.

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

Comment puis-je y parvenir?

 entrez la description de l'image ici


0 commentaires

3 Réponses :


0
votes

Vous pouvez placer votre flèche dans un objet UIView. Vous pourriez alors avoir l'UIView sur une minuterie où il a changé l'alpha correctement. En fonction du clignotement ou de la décoloration, vous pouvez néanmoins utiliser les animations UIView pour compléter l'animation souhaitée.

Je dis un uiview, au lieu d'utiliser le scrollview car vous ne voulez pas masquer le scrollview. Vous le placerez donc dans une vue dans laquelle il n’y a qu’un conteneur pour le chemin bezier.


0 commentaires

1
votes

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

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

et pour continuer l'animation du dégradé dans l'ordre cyclique comme:

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")
}


2 commentaires

Cela ajoutera un dégradé à l'ensemble de l'UIView personnalisé, pas seulement à la flèche?


vous devez remplacer self.view par votre arrowView



0
votes

Je l'ai résolu en utilisant CABasicAnimation () . Cela ajoute d'abord un calque de dégradé à UIView personnalisé, puis applique un masque dessus, puis ajoute 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)

}


0 commentaires