比如说,我有两个 CGRect,CGRect A 和 CGRect B。我的 UIView 的帧与 CGRect B 相同,但我想创建一个动画来显示 UIView 从帧 A 过渡到 B。
我试图通过更改 UIView 的转换属性来做到这一点,所以我不必过多地弄乱它的框架。但是,我需要 CGAffineTransform 来实现这一点。计算这种变换的最佳方法是什么?
比如说,我有两个 CGRect,CGRect A 和 CGRect B。我的 UIView 的帧与 CGRect B 相同,但我想创建一个动画来显示 UIView 从帧 A 过渡到 B。
我试图通过更改 UIView 的转换属性来做到这一点,所以我不必过多地弄乱它的框架。但是,我需要 CGAffineTransform 来实现这一点。计算这种变换的最佳方法是什么?
以前的答案对我不起作用。这应该有效:
extension CGAffineTransform {
init(from source: CGRect, to destination: CGRect) {
let t = CGAffineTransform.identity
.translatedBy(x: destination.midX - source.midX, y: destination.midY - source.midY)
.scaledBy(x: destination.width / source.width, y: destination.height / source.height)
self.init(a: t.a, b: t.b, c: t.c, d: t.d, tx: t.tx, ty: t.ty)
}
}
func transformFromRect(from source: CGRect, toRect destination: CGRect) -> CGAffineTransform {
return CGAffineTransform.identity
.translatedBy(x: destination.midX - source.midX, y: destination.midY - source.midY)
.scaledBy(x: destination.width / source.width, y: destination.height / source.height)
}
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)
}
+ (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;
}
我还没有找到任何一种方便的方法来解决这个问题,所以我求助于尝试过的真正的矩阵计算来实现这一点。
给定一个 CGRect A 和 CGRect B,要计算从 A 到 B 所需的转换,请执行以下操作:
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);
这是josema.vitaminew 答案的一个变体,它也考虑了纵横比(如果您正在处理视频或图像,这很有用):
+ (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;
}
一个不错的 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)
}
}
上面代码片段的最后一行需要修改如下:
transform = CGAffineTransformTranslate (transform, B.origin.x*A.size.width/B.size.width, B.origin.y*A.size.height/B.size.height);
我开始使用 Kanobius 答案,但要么我误解了他对“纵横比”一词的使用,要么他是,因为它没有按我预期的那样执行。这是我的版本,它保持原始视图的纵横比(通过将缩放应用于 H 和 W)以实现“纵横比”行为
+ (CGAffineTransform)transformFromRect:(CGRect)sourceRect toRect:(CGRect)finalRect keepingAspectRatio:(BOOL)keepingAspectRatio
{
CGAffineTransform transform = CGAffineTransformIdentity;
// since the scale transform works around the midpoints, align them before doing the transform.
transform = CGAffineTransformTranslate(transform, -(CGRectGetMidX(sourceRect)-CGRectGetMidX(finalRect)), -(CGRectGetMidY(sourceRect)-CGRectGetMidY(finalRect)));
CGFloat originalHeight = sourceRect.size.height;
CGFloat scaledHeight = finalRect.size.height;
CGFloat hScalePercentage = scaledHeight / originalHeight;
CGFloat originalWidth = sourceRect.size.width;
CGFloat scaledWidth = finalRect.size.width;
CGFloat wScalePercentage = scaledWidth / originalWidth;
if (keepingAspectRatio)
{
CGFloat scalePercentage = MIN(hScalePercentage, wScalePercentage); // the most amount of scaling == smallest float number
transform = CGAffineTransformScale(transform, scalePercentage, scalePercentage);
}
else
{
transform = CGAffineTransformScale(transform, wScalePercentage, hScalePercentage);
}
return transform;
}