2010-08-18 17 views
10

Mam widok, który chcę przeskalować i przetłumaczyć w nowe miejsce, animując go. Starałem się go osiągnąć za pomocą następującego kodu:UIView animation - Skalowanie + Tłumaczenie

[UIView beginAnimations:nil context:nil]; 
[UIView setAnimationDuration:kDurationForFullScreenAnimation]; 
[[self animatingView] setFrame:finalRect]; 
[UIView commitAnimations]; 

Efektem tego kodu jest, że widok najpierw zmienia rozmiar jego treść do danego finalRect a następnie przekłada je do nowej lokalizacji. tj. część skalująca nigdy nie jest animowana. Widok jest właśnie przekształcany do nowego rozmiaru, a następnie tłumaczony.

Ten problem jest już omówiony w kilku innych wątkach, ale żaden z nich nie wyciąga wniosków. Istnieje jednak rozwiązanie, aby użyć zegara i ustawić ramkę za każdym razem w oddzwanianiu timera, ale ma ona wadę wydajności.

Jakie jest najodpowiedniejsze rozwiązanie tego problemu, także dlaczego w pierwszym przypadku występuje ten problem?

Dzięki

Odpowiedz

33

Ustawienie ramki nie ma skali ani tłumaczenia. Używasz niewłaściwej terminologii lub używasz niewłaściwego narzędzia do pracy. Skaluj i tłumacz są wykonywane przy użyciu transformacji afinicznej Core Graphics, gdy chcesz wpłynąć na UIView (w przeciwieństwie do warstwy, która używa transformacji Core Animation).

do skalowania widoku używać

// 2x 
[rotationView setTransform:CGAffineTransformMakeScale(2.0, 2.0)]; 

Aby przetłumaczyć, użyj

// Move origin by 100 on both axis 
[rotationView setTransform:CGAffineTransformMakeTranslation(100.0, 100.0)]; 

Aby animować je, owinąć je w bloku animacji. Jeśli chcesz przekształcić widok za pomocą obu tych elementów, musisz je złączyć.

Jeśli nie chcesz w ogóle skali i tłumaczenia (transformacji), to znaczy, że chcesz zmienić ograniczenia i pozycję widoku. Są one zmieniane z połączeń do

[view setBounds:newRect]; 
[view setCenter:newCenter]; 

Gdzie newRect i newCenterCGRect i CGPoint odpowiednio, że reprezentują nową pozycję na ekranie. Ponownie, te potrzeby są zawijane w bloku animacji.

+0

Rzecz w tym, jeśli to zrobię tak, zawartość widzenia oraz wszystkich jej sub-views natychmiast zakładają newRect . Nie są animowane do nowej klatki. Tak jak na przykład, że masz imageView jako subView do animowanego widoku, obraz w imageView nie jest skalowany stopniowo. Zamiast tego obraz jest najpierw wysadzany w powietrze do nowej wartości, a następnie skala widoku + przesuwa się.Zmiana centrum działa jednak w bloku animacji, ale zmiana granic nie jest zgodna z oczekiwaniami. –

15

Oto przykład animacji Blokowanie:

CGPoint newCenter = CGPointMake(100.0,100.0); 

[UIView animateWithDuration: 1 
         delay: 0 
        options: (UIViewAnimationOptionCurveLinear | UIViewAnimationOptionAllowUserInteraction) 
       animations:^{object.center = newCenter ; object.transform = CGAffineTransformScale(CGAffineTransformIdentity, 2.0, 2.0);} 
       completion:^(BOOL finished) { } 
]; 
4

Spróbuj rozwiązanie:

CGAffineTransform s = CGAffineTransformMakeScale(0.5f,0.5f); 
    CGAffineTransform t = CGAffineTransformMakeTranslation(100, 0); 
    v2.transform = CGAffineTransformConcat(t,s); // not s,t 

operacja ta nie jest przemienne. Kolejność jest przeciwieństwem zlecenia przy korzystaniu z funkcji wygody w celu zastosowania jednej transformacji do drugiej.

i można użyć tej operacji, aby na przykład: (usunąć skali):

v2.transform = 
    CGAffineTransformConcat(CGAffineTransformInvert(s), v2.transform); 
+2

Świetna odpowiedź. Ze wszystkich moich poszukiwań, ten dostał dokładnie to, czego potrzebowałem, aby ta animacja działała dokładnie tak, jak tego potrzebuję. Próbuję zduplikować animację widoczną na Androidzie podczas wybierania pola tekstowego, które ma mniejszą etykietę, w górę iw lewo. Tylko przekształcenie skali zmniejsza etykietę, ale w dół iw prawo. Potrzebna była również transformacja tłumaczeń, ale nie mogłem znaleźć sposobu, aby obie zadziałały. Klucz CGAffineTransformConcat. Dzięki! – magnusMTB