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 CircleView
clase:
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
drawRect
función a unCAShapeLayer
. Luego, podemos usar aCABasicAnimation
para animarCAShapeLayer
lastrokeEnd
propiedad de0.0
a1.0
.strokeEnd
es una gran parte de la magia aquí; de los documentos:Si nos fijamos
strokeEnd
a0.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
CAShapeLayer
en suCircleView
'sinit
función y agregar esa capa a la vistasublayers
(también asegúrese de quitar ladrawRect
función ya que la capa será de dibujar el círculo ahora):Nota: Estamos configurando
circleLayer.strokeEnd = 0.0
para 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
addCircleView
función para que active la animación cuando agregue elCircleView
a 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
strokeEnd
self.view?.layer.addSublayer(circleLayer)
:-)startAngle:
yendAngle:
delUIBezierPath
.0
es 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.00001
yendAngle: 0 - (Double.pi / 2)
. SistartAngle
yendAngle
son iguales, el círculo no se dibujará, por lo que resta un desplazamiento muy pequeño alstartAngle
Respuesta de Mikes actualizada para Swift 3.0
Para llamar a la función:
fuente
M_PI
está en desuso, utilíceloCGFloat.pi
en 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 anCALayer
En 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 setup
Uso:
código de muestra para
frame manually
、storyboard setup
、autolayout setup
fuente