2012-05-23 13 views
12

Powiedz, mam dwie CGRects, CGRect A i B. My rama CGRect UIView jest taka sama jak CGRect B, ale chcę stworzyć animację przedstawiający UIView przejście z ramka A do B.Czy istnieje sposób obliczenia CGAffineTransform potrzebnej do przekształcenia widoku z klatki A do ramki B?

Próbuję Aby to zrobić, zmieniając właściwość transformacji UIView, więc nie muszę zbytnio zawodzić z jej ramką. Jednak potrzebuję CGAffineTransform, aby to umożliwić. Jaki jest najlepszy sposób obliczenia tej transformacji?

+0

Czy istnieje jakiś ważny powód, aby nie animować własności ramki od CGRect A do CGRect B? –

+1

Nie naciskając. Powodem jest jednak to, że utrzymywanie statycznej ramki widoku i używanie transformacji do jej przemieszczania znacznie upraszcza śledzenie jej podczas bardziej złożonych zmian stanu (takich jak automatyczna rotacja). – SpacyRicochet

+0

Interesujące podejście. +1 :) –

Odpowiedz

7

Nie byłem w stanie znaleźć dla tego celu żadnego rodzaju wygody, dlatego uciekłem się do sprawdzonych obliczeń macierzy, aby to osiągnąć.

Biorąc pod uwagę CGRect A i CGRect B, do obliczenia transformacji potrzebne, aby przejść z punktu A do B, wykonaj następujące czynności:

CGAffineTransform transform = CGAffineTransformTranslate(CGAffineTransformIdentity, -A.origin.x, -A.origin.y); 
transform = CGAffineTransformScale(transform, 1/A.size.width, 1/A.size.height); 
transform = CGAffineTransformScale(transform, B.size.width, B.size.height); 
transform = CGAffineTransformTranslate(transform, B.origin.x, B.origin.y); 
1

Ostatni wiersz w powyższym fragmencie kodu należy zmienić w następujący sposób:

transform = CGAffineTransformTranslate (transform, B.origin.x*A.size.width/B.size.width, B.origin.y*A.size.height/B.size.height);

26

dotychczasowe odpowiedzi nie działa dla mnie. To powinno działać:

+ (CGAffineTransform) transformFromRect:(CGRect)sourceRect toRect:(CGRect)finalRect { 
    CGAffineTransform transform = CGAffineTransformIdentity; 
    transform = CGAffineTransformTranslate(transform, -(CGRectGetMidX(sourceRect)-CGRectGetMidX(finalRect)), -(CGRectGetMidY(sourceRect)-CGRectGetMidY(finalRect))); 
    transform = CGAffineTransformScale(transform, finalRect.size.width/sourceRect.size.width, finalRect.size.height/sourceRect.size.height); 

    return transform; 
} 

Swift:

func transformFromRect(from: CGRect, toRect to: CGRect) -> CGAffineTransform { 
    let transform = CGAffineTransformMakeTranslation(CGRectGetMidX(to)-CGRectGetMidX(from), CGRectGetMidY(to)-CGRectGetMidY(from)) 
    return CGAffineTransformScale(transform, to.width/from.width, to.height/from.height) 
} 
+0

jeden z najlepszych fragmentów, jakie kiedykolwiek spotkałem. Dobra robota – YichenBman

3

Oto wariacja na josema.vitaminew answer który również uważa, proporcje (przydatne, jeśli pracujesz z filmów lub zdjęć):

+ (CGAffineTransform)transformFromRect:(CGRect)sourceRect toRect:(CGRect)finalRect keepingAspectRatio:(BOOL)keepingAspectRatio { 
    CGAffineTransform transform = CGAffineTransformIdentity; 

    transform = CGAffineTransformTranslate(transform, -(CGRectGetMidX(sourceRect)-CGRectGetMidX(finalRect)), -(CGRectGetMidY(sourceRect)-CGRectGetMidY(finalRect))); 

    if (keepingAspectRatio) { 
     CGFloat sourceAspectRatio = sourceRect.size.width/sourceRect.size.height; 
     CGFloat finalAspectRatio = finalRect.size.width/finalRect.size.height; 

     if (sourceAspectRatio > finalAspectRatio) { 
      transform = CGAffineTransformScale(transform, finalRect.size.height/sourceRect.size.height, finalRect.size.height/sourceRect.size.height); 
     } else { 
      transform = CGAffineTransformScale(transform, finalRect.size.width/sourceRect.size.width, finalRect.size.width/sourceRect.size.width); 
     } 
    } else { 
     transform = CGAffineTransformScale(transform, finalRect.size.width/sourceRect.size.width, finalRect.size.height/sourceRect.size.height); 
    } 

    return transform; 
} 
2

A ładne rozwiązanie Swift 3:

extension CGAffineTransform { 
    init(from: CGRect, toRect to: CGRect) { 
     self.init(translationX: to.midX-from.midX, y: to.midY-from.midY) 
     self = self.scaledBy(x: to.width/from.width, y: to.height/from.height) 
    } 
}