2012-05-23 10 views
12

Dire, ho due CGRects, CGRect A e telaio di CGRect B. Il mio UIView è la stessa CGRect B, ma voglio creare un'animazione che mostra l'UIView transizione da cornice A a B.C'è un modo per calcolare il CGAffineTransform necessario per trasformare una vista dal frame A al frame B?

sto cercando per fare ciò cambiando la proprietà di trasformazione di UIView, quindi non devo scherzare troppo con la sua cornice. Tuttavia, ho bisogno di CGAffineTransform per renderlo possibile. Qual è il modo migliore per calcolare questa trasformazione?

+0

C'è qualche motivo per non animare semplicemente la proprietà frame da CGRect A a CGRect B? –

+1

Non premendo. Ma la ragione è che mantenere il frame della vista statico e usare le trasformazioni per spostarlo in modo significativo semplifica il modo in cui tenerlo traccia durante cambiamenti di stato più complessi (come la rotazione automatica). – SpacyRicochet

+0

Approccio interessante. +1 :) –

risposta

7

Non sono stato in grado di trovare un metodo di convenienza di alcun tipo per questo, quindi ho fatto ricorso a calcoli matricolari provati e veri per raggiungere questo obiettivo.

Dato un CGRect A e CGRect B, per calcolare la trasformazione necessaria per passare da A a B, effettuare le seguenti operazioni:

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

L'ultima linea nel frammento di codice sopra deve essere modificato come segue:

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

26

Le risposte precedenti non ha funzionato per me. Questo dovrebbe funzionare:

+ (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

uno dei migliori frammenti che abbia mai visto. Molto bene – YichenBman

3

Ecco una variazione su josema.vitaminew answer che considera anche le proporzioni (utile se si lavora con video o immagini):

+ (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 bella soluzione 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) 
    } 
}