Créer une propriété animable personnalisée
Sur UIView
vous pouvez modifier la couleur d'arrière-plan animée. Et sur un UISlideView
Vous pouvez changer la valeur animée.
Pouvez-vous ajouter une propriété personnalisée à votre propre sous-classe UIView
afin qu'elle puisse être animée?
Si j'ai un CGPath
dans mon UIView
Alors je peux en animer le dessin en changeant le pourcentage dessiné du chemin.
Puis-je encapsuler cette animation dans la sous-classe.
C'est-à-dire que j'ai un UIView
avec un {[4] } qui crée un cercle.
Si le cercle n'est pas là, il représente 0%. Si le cercle est plein, il représente 100%. Je peux dessiner n'importe quelle valeur en changeant le pourcentage tiré du chemin. Je peux également animer le changement (dans la sous-classe UIView) en animant le pourcentage du CGPath
et en redessinant le chemin.
Puis-je définir une propriété (c'est-à-dire un pourcentage) sur le UIView
afin que je puisse coller le changement dans un bloc UIView animateWithDuration
et qu'il anime le changement du pourcentage du chemin?
J'espère avoir expliqué ce que je ferais comme de bien faire.
Essentiellement, tout ce que je veux faire est quelque chose comme...
[UIView animateWithDuration:1.0
animations:^{
myCircleView.percentage = 0.7;
}
completion:nil];
Et le chemin du cercle s'Anime au pourcentage donné.
4 réponses
Si vous étendez CALayer et implémentez votre
- (void) drawInContext:(CGContextRef) context
Vous pouvez créer une propriété animable en remplaçant needsDisplayForKey
(dans votre classe CALayer personnalisée) comme ceci:
+ (BOOL) needsDisplayForKey:(NSString *) key {
if ([key isEqualToString:@"percentage"]) {
return YES;
}
return [super needsDisplayForKey:key];
}
Bien sûr, vous devez également avoir un @property
appelé percentage
. A partir de Maintenant, vous pouvez animer la propriété percentage en utilisant core animation. Je n'ai pas vérifié si cela fonctionne aussi en utilisant l'appel [UIView animateWithDuration...]
. Cela pourrait fonctionner. Mais cela a fonctionné pour moi:
CABasicAnimation *animation = [CABasicAnimation animationWithKeyPath:@"percentage"];
animation.duration = 1.0;
animation.fromValue = [NSNumber numberWithDouble:0];
animation.toValue = [NSNumber numberWithDouble:100];
[myCustomLayer addAnimation:animation forKey:@"animatePercentage"];
Oh, et pour utiliser yourCustomLayer
avec myCircleView
, ne ce:
[myCircleView.layer addSublayer:myCustomLayer];
Exemple Swift 3 complet:
public class CircularProgressView: UIView {
public dynamic var progress: CGFloat = 0 {
didSet {
progressLayer.progress = progress
}
}
fileprivate var progressLayer: CircularProgressLayer {
return layer as! CircularProgressLayer
}
override public class var layerClass: AnyClass {
return CircularProgressLayer.self
}
override public func action(for layer: CALayer, forKey event: String) -> CAAction? {
if event == #keyPath(CircularProgressLayer.progress),
let action = action(for: layer, forKey: #keyPath(backgroundColor)) as? CAAnimation {
let animation = CABasicAnimation()
animation.keyPath = #keyPath(CircularProgressLayer.progress)
animation.fromValue = progressLayer.progress
animation.toValue = progress
animation.beginTime = action.beginTime
animation.duration = action.duration
animation.speed = action.speed
animation.timeOffset = action.timeOffset
animation.repeatCount = action.repeatCount
animation.repeatDuration = action.repeatDuration
animation.autoreverses = action.autoreverses
animation.fillMode = action.fillMode
animation.timingFunction = action.timingFunction
animation.delegate = action.delegate
self.layer.add(animation, forKey: #keyPath(CircularProgressLayer.progress))
}
return super.action(for: layer, forKey: event)
}
}
/*
* Concepts taken from:
* https://stackoverflow.com/a/37470079
*/
fileprivate class CircularProgressLayer: CALayer {
@NSManaged var progress: CGFloat
let startAngle: CGFloat = 1.5 * .pi
let twoPi: CGFloat = 2 * .pi
let halfPi: CGFloat = .pi / 2
override class func needsDisplay(forKey key: String) -> Bool {
if key == #keyPath(progress) {
return true
}
return super.needsDisplay(forKey: key)
}
override func draw(in ctx: CGContext) {
super.draw(in: ctx)
UIGraphicsPushContext(ctx)
//Light Grey
UIColor.lightGray.setStroke()
let center = CGPoint(x: bounds.midX, y: bounds.midY)
let strokeWidth: CGFloat = 4
let radius = (bounds.size.width / 2) - strokeWidth
let path = UIBezierPath(arcCenter: center, radius: radius, startAngle: 0, endAngle: twoPi, clockwise: true)
path.lineWidth = strokeWidth
path.stroke()
//Red
UIColor.red.setStroke()
let endAngle = (twoPi * progress) - halfPi
let pathProgress = UIBezierPath(arcCenter: center, radius: radius, startAngle: startAngle, endAngle: endAngle , clockwise: true)
pathProgress.lineWidth = strokeWidth
pathProgress.lineCapStyle = .round
pathProgress.stroke()
UIGraphicsPopContext()
}
}
let circularProgress = CircularProgressView(frame: CGRect(x: 0, y: 0, width: 80, height: 80))
UIView.animate(withDuration: 2, delay: 0, options: .curveEaseInOut, animations: {
circularProgress.progress = 0.76
}, completion: nil)
Il y a un grand article objc ici , qui va dans les détails sur la façon dont cela fonctionne
Ainsi Qu'un objc projet qui utilise les mêmes concepts ici:
Essentiellement action (pour layer:) sera appelée lorsqu'un objet est animé à partir d'un bloc d'animation, nous pouvons démarrer nos propres animations avec les mêmes propriétés (volées de la propriété backgroundColor) et animer le changement.
Pour ceux qui ont besoin de plus de détails à ce sujet comme je l'ai fait:
Il y a un exemple cool d'Apple couvrant cette question.
Par exemple, grâce à cela, j'ai trouvé que vous n'avez pas réellement besoin d'ajouter votre couche personnalisée en tant que sous-couche (comme le suggère @Tom van zummeren). Au lieu de cela, il suffit d'ajouter une méthode de classe à votre classe de vue:
+ (Class)layerClass
{
return [CustomLayer class];
}
J'espère que ça aide quelqu'un.
Vous devrez implémenter la partie pourcentage vous-même. vous pouvez remplacer le code de dessin de calque pour dessiner votre cgpath accroding à la valeur de pourcentage définie. la caisse de la core animation guide de programmation et types d'animation et le calendrier guide de