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?
3 Réponses :
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.
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")
}
Cela ajoutera un dégradé à l'ensemble de l'UIView personnalisé, pas seulement à la flèche?
vous devez remplacer self.view par votre arrowView
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)
}