Estoy buscando una forma de animar el dibujo de un círculo. He podido crear el círculo, pero lo dibuja todo junto.
Aquí está mi CircleViewclase:
import UIKit
class CircleView: UIView {
override init(frame: CGRect) {
super.init(frame: frame)
self.backgroundColor = UIColor.clearColor()
}
required init(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
override func drawRect(rect: CGRect) {
// Get the Graphics Context
var context = UIGraphicsGetCurrentContext();
// Set the circle outerline-width
CGContextSetLineWidth(context, 5.0);
// Set the circle outerline-colour
UIColor.redColor().set()
// Create Circle
CGContextAddArc(context, (frame.size.width)/2, frame.size.height/2, (frame.size.width - 10)/2, 0.0, CGFloat(M_PI * 2.0), 1)
// Draw
CGContextStrokePath(context);
}
}
Y así es como lo agrego a la jerarquía de vista en mi controlador de vista:
func addCircleView() {
let diceRoll = CGFloat(Int(arc4random_uniform(7))*50)
var circleWidth = CGFloat(200)
var circleHeight = circleWidth
// Create a new CircleView
var circleView = CircleView(frame: CGRectMake(diceRoll, 0, circleWidth, circleHeight))
view.addSubview(circleView)
}
¿Hay alguna forma de animar el dibujo del círculo durante 1 segundo?
Por ejemplo, a mitad de la animación se vería algo así como la línea azul en esta imagen:


Respuestas:
La forma más sencilla de hacer esto es utilizar el poder de la animación central para hacer la mayor parte del trabajo por usted. Para hacer eso, tendremos que mover su código de dibujo circular de su
drawRectfunción a unCAShapeLayer. Luego, podemos usar aCABasicAnimationpara animarCAShapeLayerlastrokeEndpropiedad de0.0a1.0.strokeEndes una gran parte de la magia aquí; de los documentos:Si nos fijamos
strokeEnda0.0, no va a dibujar cualquier cosa. Si lo configuramos1.0, dibujará un círculo completo. Si lo configuramos0.5, dibujará un semicírculo. etc.Así que, para empezar, vamos a crear una
CAShapeLayeren suCircleView'sinitfunción y agregar esa capa a la vistasublayers(también asegúrese de quitar ladrawRectfunción ya que la capa será de dibujar el círculo ahora):Nota: Estamos configurando
circleLayer.strokeEnd = 0.0para que el círculo no se dibuje de inmediato.Ahora, agreguemos una función que podamos llamar para activar la animación del círculo:
Luego, todo lo que tenemos que hacer es cambiar su
addCircleViewfunción para que active la animación cuando agregue elCircleViewa susuperview:Todo eso junto debería verse así:
Nota: No se repetirá así, permanecerá en un círculo completo después de que se anime.
fuente
strokeEndself.view?.layer.addSublayer(circleLayer):-)startAngle:yendAngle:delUIBezierPath.0es la posición 3, por lo que la posición 12 sería 90 ° menos que eso, que es -π / 2 en radianes. Entonces, los parámetros seríanstartAngle: CGFloat(-M_PI_2), endAngle: CGFloat((M_PI * 2.0) - M_PI_2).startAngle: (0 - (Double.pi / 2)) + 0.00001yendAngle: 0 - (Double.pi / 2). SistartAngleyendAngleson iguales, el círculo no se dibujará, por lo que resta un desplazamiento muy pequeño alstartAngleRespuesta de Mikes actualizada para Swift 3.0
Para llamar a la función:
fuente
M_PIestá en desuso, utilíceloCGFloat.pien su lugar.¡La respuesta de Mike es genial! Otra forma agradable y sencilla de hacerlo es usar drawRect combinado con setNeedsDisplay (). Parece lento, pero no lo es :-)
Queremos dibujar un círculo empezando por la parte superior, que tiene -90 ° y termina en 270 °. El centro del círculo es (centerX, centerY), con un radio dado. CurrentAngle es el ángulo actual del punto final del círculo, que va desde minAngle (-90) a maxAngle (270).
En drawRect, especificamos cómo se supone que se muestra el círculo:
El problema es que en este momento, como currentAngle no cambia, el círculo es estático y ni siquiera se muestra, como currentAngle = minAngle.
Luego creamos un temporizador, y cada vez que se dispara, aumentamos currentAngle. En la parte superior de su clase, agregue el tiempo entre dos incendios:
En su init, agregue el temporizador:
Podemos agregar la función que se llamará cuando se active el temporizador:
Lamentablemente, al ejecutar la aplicación, no se muestra nada porque no especificamos el sistema que debería dibujar nuevamente. Esto se hace llamando a setNeedsDisplay (). Aquí está la función de temporizador actualizada:
_ _ _
Todo el código que necesita se resume aquí:
Si desea cambiar la velocidad, simplemente modifique la función updateTimer o la velocidad a la que se llama a esta función. Además, es posible que desee invalidar el temporizador una vez que se complete el círculo, lo que olvidé hacer :-)
NB: Para agregar el círculo en su guión gráfico, simplemente agregue una vista, selecciónela, vaya a su Inspector de identidad y, como Clase , especifique CircleClosing .
¡Salud! bRo
fuente
Si desea un controlador de finalización, esta es otra solución similar a la de Mike S, realizada en Swift 3.0
Con el controlador de finalización, puede ejecutar la animación nuevamente, ya sea llamando de forma recursiva a la misma función para hacer la animación nuevamente (lo que no se verá muy bien), o puede tener una función inversa que se encadenará continuamente hasta que se cumpla una condición , por ejemplo:
Para hacerlo aún más elegante, puede cambiar la dirección de la animación de esta manera:
fuente
No solo puede subclase an
UIView, también puede ir un poco más profundo, subclase anCALayerEn otras palabras, el strokeEnd de CoreAnimation está bien. Llamar al sorteo de CALayer (en ctx :) con frecuencia también está bien
y la gorra de línea redonda es agradable
El punto clave es anular el método de CALayer
action(forKey:)La subclase interna de CAShapeLayer
métodos de ayuda
utilizar una subclase UIView, con el CALayer personalizado interno
Uso:
con una imagen indicadora para configurar el ángulo
fuente
actualizando la respuesta de @Mike S para Swift 5
funciona para
frame manually、storyboard setup、autolayout setupUso:
código de muestra para
frame manually、storyboard setup、autolayout setupfuente