Szukam sposobu na ożywienie rysunku koła. Udało mi się stworzyć okrąg, ale to wszystko łączy.
Oto moja CircleView
klasa:
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);
}
}
A oto jak dodać to do hierarchii widoków w moim kontrolerze widoku:
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)
}
Czy istnieje sposób, aby animować rysowanie koła przez 1 sekundę?
Przykład: w trakcie animacji wyglądałoby to mniej więcej tak, jak niebieska linia na tym obrazku:
Odpowiedzi:
Najłatwiejszym sposobem na to jest wykorzystanie mocy animacji do wykonywania większości pracy za Ciebie. Aby to zrobić, będziemy musieli przenieść kod rysowania okręgu z
drawRect
funkcji do plikuCAShapeLayer
. Wtedy możemy użyćCABasicAnimation
do animowaniaCAShapeLayer
„sstrokeEnd
nieruchomości od0.0
do1.0
.strokeEnd
jest tutaj dużą częścią magii; z dokumentów:Jeśli stawiamy
strokeEnd
na0.0
to nie zwróci nic. Jeśli ustawimy to na1.0
, zakreśli pełne koło. Jeśli ustawimy to na0.5
, narysuje półkole. itp.Tak więc, aby rozpocząć, pozwala stworzyć
CAShapeLayer
w swoimCircleView
„sinit
funkcji i dodać tę warstwę do widoku użytkownikasublayers
(również należy usunąćdrawRect
funkcję ponieważ warstwa będzie rysowanie okręgu teraz):Uwaga: ustawiamy
circleLayer.strokeEnd = 0.0
tak, aby okrąg nie był od razu rysowany.Teraz dodajmy funkcję, którą możemy wywołać, aby uruchomić animację koła:
Następnie wszystko, co musimy zrobić, to zmienić
addCircleView
funkcję tak, aby uruchamiała animację po dodaniuCircleView
do jejsuperview
:Wszystko razem powinno wyglądać mniej więcej tak:
Uwaga: to się nie powtórzy, po animacji pozostanie pełne koło.
źródło
strokeEnd
self.view?.layer.addSublayer(circleLayer)
:-)startAngle:
i pliku . jest pozycją 3, więc pozycja 12 byłaby o 90 ° mniejsza niż ta, która wynosi -π / 2 w radianach. Tak więc parametry byłyby .endAngle:
UIBezierPath
0
startAngle: CGFloat(-M_PI_2), endAngle: CGFloat((M_PI * 2.0) - M_PI_2)
startAngle: (0 - (Double.pi / 2)) + 0.00001
iendAngle: 0 - (Double.pi / 2)
. JeślistartAngle
iendAngle
są takie same, koło nie zostanie narysowane, dlatego odejmujesz bardzo małe przesunięcie dostartAngle
Odpowiedź Mikesa zaktualizowana dla wersji Swift 3.0
Aby wywołać funkcję:
źródło
M_PI
jest przestarzały - użyjCGFloat.pi
zamiast tego.Odpowiedź Mike'a jest świetna! Innym przyjemnym i prostym sposobem jest użycie drawRect w połączeniu z setNeedsDisplay (). Wydaje się, że jest opóźniony, ale nie :-)
Chcemy narysować okrąg zaczynający się od góry, który wynosi -90 °, a kończy się na 270 °. Środek okręgu to (centerX, centerY) o zadanym promieniu. CurrentAngle to bieżący kąt punktu końcowego okręgu, od minAngle (-90) do maxAngle (270).
W drawRect określamy, jak ma się wyświetlać okrąg:
Problem polega na tym, że teraz, ponieważ currentAngle się nie zmienia, okrąg jest statyczny i nawet się nie wyświetla, jako currentAngle = minAngle.
Następnie tworzymy licznik czasu i ilekroć ten licznik jest uruchamiany, zwiększamy wartość currentAngle. U góry klasy dodaj czas między dwoma pożarami:
W swoim init dodaj licznik czasu:
Możemy dodać funkcję, która zostanie wywołana po uruchomieniu timera:
Niestety, podczas uruchamiania aplikacji nic się nie wyświetla, ponieważ nie określiliśmy systemu, który ma rysować ponownie. Odbywa się to przez wywołanie setNeedsDisplay (). Oto zaktualizowana funkcja timera:
_ _ _
Tutaj podsumowano cały potrzebny kod:
Jeśli chcesz zmienić prędkość, po prostu zmodyfikuj funkcję updateTimer lub szybkość, z jaką ta funkcja jest wywoływana. Możesz również chcieć unieważnić licznik czasu, gdy koło się zakończy, o czym zapomniałem :-)
NB: Aby dodać okrąg do swojej scenorysu, po prostu dodaj widok, wybierz go, przejdź do jego Inspektora tożsamości i jako Klasa określ CircleClosing .
Twoje zdrowie! bracie
źródło
Jeśli potrzebujesz obsługi zakończenia, jest to kolejne rozwiązanie podobne do tego autorstwa Mike'a S, wykonane w Swift 3.0
Dzięki obsłudze zakończenia możesz ponownie uruchomić animację albo przez rekurencyjne wywołanie tej samej funkcji, aby ponownie wykonać animację (co nie będzie wyglądać zbyt dobrze), lub możesz mieć odwróconą funkcję, która będzie nieprzerwanie łączyć, dopóki warunek nie zostanie spełniony , na przykład:
Aby było jeszcze bardziej wyszukane, możesz zmienić kierunek animacji w następujący sposób:
źródło
Nie tylko możesz podklasować plik
UIView
, możesz też przejść nieco głębiej, podklasować plikCALayer
Innymi słowy, metoda strokeEnd w programie CoreAnimation jest w porządku. Często sprawdzanie losowania CALayera (w ctx :) jest również OK
a okrągła nasadka jest ładna
Kluczową kwestią jest zastąpienie metody CALayera
action(forKey:)
Wewnętrzna podklasa CAShapeLayer
metody pomocnicze
użyj podklasy UIView z wewnętrznym niestandardowym CALayer
Stosowanie:
z obrazem wskaźnika do ustawiania kąta
źródło
aktualizacja odpowiedzi @Mike S dla Swift 5
pracuje dla
frame manually
、storyboard setup
、autolayout setup
Stosowanie :
przykładowy kod dla
frame manually
、storyboard setup
、autolayout setup
źródło