Estou procurando uma maneira de animar o desenho de um círculo. Consegui criar o círculo, mas ele reúne tudo.
Aqui está minha CircleView
aula:
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);
}
}
E aqui está como eu adiciono à hierarquia de visualização em meu controlador de visualização:
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)
}
Existe uma maneira de animar o desenho do círculo em 1 segundo?
Exemplo, no meio da animação seria algo como a linha azul nesta imagem:
Respostas:
A maneira mais fácil de fazer isso é usar o poder da animação principal para fazer a maior parte do trabalho para você. Para fazer isso, teremos que mover seu código de desenho de círculo de sua
drawRect
função para aCAShapeLayer
. Então, podemos usar umaCABasicAnimation
para animarCAShapeLayer
'sstrokeEnd
propriedade a partir0.0
de1.0
.strokeEnd
é uma grande parte da magia aqui; dos documentos:Se definirmos
strokeEnd
para0.0
, não desenhará nada. Se definirmos para1.0
, ele desenhará um círculo completo. Se definirmos como0.5
, ele desenhará um semicírculo. etc.Então, para começar, vamos criar um
CAShapeLayer
na suaCircleView
'sinit
função e adicionar essa camada à parte de vistasublayers
(também certifique-se de remover adrawRect
função desde a camada será desenhar o círculo agora):Nota: estamos definindo
circleLayer.strokeEnd = 0.0
para que o círculo não seja desenhado imediatamente.Agora, vamos adicionar uma função que podemos chamar para acionar a animação do círculo:
Então, tudo o que precisamos fazer é alterar sua
addCircleView
função para que ela acione a animação quando você adicionar oCircleView
asuperview
:Tudo isso junto deve ser parecido com isto:
Observação: não se repetirá assim, ficará um círculo completo após a animação.
fonte
strokeEnd
self.view?.layer.addSublayer(circleLayer)
:-)startAngle:
eendAngle:
doUIBezierPath
.0
é a posição 3, então a posição 12 seria 90 ° menor que isso, que é -π / 2 em radianos. Então, os parâmetros seriamstartAngle: CGFloat(-M_PI_2), endAngle: CGFloat((M_PI * 2.0) - M_PI_2)
.startAngle: (0 - (Double.pi / 2)) + 0.00001
eendAngle: 0 - (Double.pi / 2)
. SestartAngle
eendAngle
forem iguais, o círculo não será desenhado, é por isso que você subtrai um deslocamento muito pequeno parastartAngle
Resposta de Mike atualizada para Swift 3.0
Para chamar a função:
fonte
M_PI
está obsoleto - use em seuCGFloat.pi
lugar.A resposta de Mike é ótima! Outra maneira simples e agradável de fazer isso é usar drawRect combinado com setNeedsDisplay (). Parece lento, mas não é :-)
Queremos desenhar um círculo começando do topo, que é -90 ° e termina em 270 °. O centro do círculo é (centerX, centerY), com um determinado raio. CurrentAngle é o ângulo atual do ponto final do círculo, indo de minAngle (-90) a maxAngle (270).
Em drawRect, especificamos como o círculo deve ser exibido:
O problema é que agora, como currentAngle não está mudando, o círculo é estático, e nem mesmo é mostrado, como currentAngle = minAngle.
Em seguida, criamos um cronômetro e, sempre que esse cronômetro dispara, aumentamos o currentAngle. No início da classe, adicione o tempo entre dois incêndios:
Em seu init, adicione o cronômetro:
Podemos adicionar a função que será chamada quando o cronômetro disparar:
Infelizmente, ao executar o aplicativo, nada é exibido porque não especificamos o sistema para que ele desenhe novamente. Isso é feito chamando setNeedsDisplay (). Aqui está a função de cronômetro atualizada:
_ _ _
Todo o código de que você precisa está resumido aqui:
Se você quiser alterar a velocidade, basta modificar a função updateTimer, ou a taxa em que esta função é chamada. Além disso, você pode querer invalidar o cronômetro quando o círculo estiver completo, o que eu esqueci de fazer :-)
NB: Para adicionar o círculo em seu storyboard, basta adicionar uma visualização, selecioná-la, ir para o Inspetor de identidade e, como Classe , especificar CircleClosing .
Felicidades! Mano
fonte
Se você quer um gerenciador de completação, esta é outra solução similar a de Mike S, feita em Swift 3.0
Com o manipulador de conclusão, você pode executar a animação novamente chamando recursivamente a mesma função para fazer a animação novamente (o que não parecerá muito bom), ou você pode ter uma função reversa que irá encadear continuamente até que uma condição seja atendida , por exemplo:
Para torná-lo ainda mais elaborado, você pode alterar a direção da animação assim:
fonte
Não só você pode criar uma subclasse de um
UIView
, você também pode ir um pouco mais fundo, subclasse umCALayer
Em outras palavras, o strokeEnd do CoreAnimation está OK. Chamar o sorteio de CALayer (em ctx :) frequentemente também está OK
e o limite de linha redondo é bom
O ponto chave é substituir o método do CALayer
action(forKey:)
A subclasse interna de CAShapeLayer
métodos auxiliares
usar uma subclasse UIView, com o CALayer personalizado interno
Uso:
com uma imagem indicadora para definir o ângulo
fonte
atualizando a resposta de @Mike S para o Swift 5
trabalha para
frame manually
、storyboard setup
、autolayout setup
Uso:
código de amostra para
frame manually
、storyboard setup
、autolayout setup
fonte