Iphone 应用UIView变换后查找帧坐标(CGAffineTransform)
我使用Iphone 应用UIView变换后查找帧坐标(CGAffineTransform),iphone,ios,objective-c,uiview,cgaffinetransform,Iphone,Ios,Objective C,Uiview,Cgaffinetransform,我使用CGAffineTransform [view setTransform:newTransform]; 应用变换后,帧值保持不变,但如何查找此帧的“旋转”或变换值 (来源:) 我想要旋转帧边的精确坐标,即a、b、c、d点。您可以使用基本三角法找到旋转视图的坐标。以下是您如何做到这一点: 第一步是了解视图的宽度和高度。将它们除以2,得到三角形的相邻边和相对边(分别为青色和绿色)。在上面的示例中,宽度=300,高度=300。所以邻接边=150,对边=150 找到斜边(红色)。为此,您可以
CGAffineTransform
[view setTransform:newTransform];
应用变换后,帧值保持不变,但如何查找此帧的“旋转”或变换值
(来源:)
我想要旋转帧边的精确坐标,即a、b、c、d点。您可以使用基本三角法找到旋转视图的坐标。以下是您如何做到这一点:
h^2=a^2+b^2
。应用这个公式后,我们发现斜边=212.13cos(θ)=(h^2+a^2-o^2)/2*h*o
。应用此公式后,我们发现θ=0.785(弧度)。要将其转换为度,我们应用公式度=弧度*180/PI
=45(度)。这是斜边的初始(偏移)角度。认识到这一点非常重要。如果视图的旋转为零,则斜边的偏移角为45度。我们很快就需要西塔了ui旋转手势识别器
旋转方形视图。这个类有一个“旋转”属性,它告诉我们视图旋转了多少。该值以弧度为单位。在上面的示例中,旋转为0.3597弧度。要将其转换为度,我们使用公式度=弧度*PI/180
。应用公式后,我们发现旋转角度为20.61度width=cos(旋转角度-θ)*斜边
,对于高度,我们使用公式height=sen(旋转角度-θ)
。我们必须从旋转角度中减去θ(弧度!),因为θ是初始偏移量。这样看:当旋转角度为零时,斜边的角度为45度。应用这些公式后,我们发现宽度=193.20,高度=87.60// Get the center point
CGPoint squareCenter = self.squareView.center;
// Get the blue point coordinates
CGPoint bluePointCoordinates = CGPointMake(squareCenter.x + width, squareCenter.y + height);
蓝点坐标为(963.20272.40)
为了更好地理解这些公式,请参见以下链接:
/* Params:
/ viewCenter: The center point (in superView coordinates) of your view
/ width: The total width of your view
/ height: The total height of your view
/ angleOfRotation: The rotation angle of your view. Can be either DEGREES or RADIANS
/ degrees: A boolean flag indicating whether 'angleOfRotation' is degrees
/ or radians. E.g.: If 'angleOfRotation' is expressed in degrees
/ this parameter must be 'YES'
*/
-(CGPoint)calculateTopRightCoordinatesFromViewCenter:(CGPoint)viewCenter viewWidth:(CGFloat)viewWidth viewHeight:(CGFloat)viewHeight angleOfRotation:(CGFloat)angleOfRotation degrees:(BOOL)degrees {
CGFloat adjacent = viewWidth/2.0;
CGFloat opposite = viewHeight/2.0;
CGFloat hipotenuse = sqrtf(powf(adjacent, 2.0) + pow(opposite, 2.0));
CGFloat thetaRad = acosf((powf(hipotenuse, 2.0) + powf(adjacent, 2.0) - pow(opposite, 2.0)) / (2 * hipotenuse * adjacent));
CGFloat angleRad = 0.0;
if (degrees) {
angleRad = angleOfRotation*M_PI/180.0;
} else {
angleRad = angleOfRotation;
}
CGFloat widthOffset = cosf(angleRad - thetaRad) * hipotenuse;
CGFloat heightOffset = sinf(angleRad - thetaRad) * hipotenuse;
CGPoint offsetPoint = CGPointMake(viewCenter.x + widthOffset, viewCenter.y + heightOffset);
return offsetPoint;
}
希望这有帮助 您应该使用:
CGPoint CGPointApplyAffineTransform (
CGPoint point,
CGAffineTransform t
);
若要获取特定点,请使用视图的边界和中心,然后应用视图的变换以在变换后获取新点。这比添加专门用于旋转变换的代码要好,因为它可以支持任何变换以及链接。需要记住的一点是,变换会更改坐标系,因此您需要能够在父视图和子视图(变换)之间进行转换。此外,变换保留变换对象的中心,但不保留任何其他坐标。所以你需要根据中心来计算。你需要几个助手。(我从Erica Sadun的书Core iOS开发者食谱中获得了以下大部分方法) 我通常在UIView中将其作为一个类别添加 为了将子对象的坐标转换为父对象的坐标,您需要以下内容:
// helper to get pre transform frame
-(CGRect)originalFrame {
CGAffineTransform currentTransform = self.transform;
self.transform = CGAffineTransformIdentity;
CGRect originalFrame = self.frame;
self.transform = currentTransform;
return originalFrame;
}
// helper to get point offset from center
-(CGPoint)centerOffset:(CGPoint)thePoint {
return CGPointMake(thePoint.x - self.center.x, thePoint.y - self.center.y);
}
// helper to get point back relative to center
-(CGPoint)pointRelativeToCenter:(CGPoint)thePoint {
return CGPointMake(thePoint.x + self.center.x, thePoint.y + self.center.y);
}
// helper to get point relative to transformed coords
-(CGPoint)newPointInView:(CGPoint)thePoint {
// get offset from center
CGPoint offset = [self centerOffset:thePoint];
// get transformed point
CGPoint transformedPoint = CGPointApplyAffineTransform(offset, self.transform);
// make relative to center
return [self pointRelativeToCenter:transformedPoint];
}
// now get your corners
-(CGPoint)newTopLeft {
CGRect frame = [self originalFrame];
return [self newPointInView:frame.origin];
}
-(CGPoint)newTopRight {
CGRect frame = [self originalFrame];
CGPoint point = frame.origin;
point.x += frame.size.width;
return [self newPointInView:point];
}
-(CGPoint)newBottomLeft {
CGRect frame = [self originalFrame];
CGPoint point = frame.origin;
point.y += frame.size.height;
return [self newPointInView:point];
}
-(CGPoint)newBottomRight {
CGRect frame = [self originalFrame];
CGPoint point = frame.origin;
point.x += frame.size.width;
point.y += frame.size.height;
return [self newPointInView:point];
}
Swift 4
extension UIView {
/// Helper to get pre transform frame
var originalFrame: CGRect {
let currentTransform = transform
transform = .identity
let originalFrame = frame
transform = currentTransform
return originalFrame
}
/// Helper to get point offset from center
func centerOffset(_ point: CGPoint) -> CGPoint {
return CGPoint(x: point.x - center.x, y: point.y - center.y)
}
/// Helper to get point back relative to center
func pointRelativeToCenter(_ point: CGPoint) -> CGPoint {
return CGPoint(x: point.x + center.x, y: point.y + center.y)
}
/// Helper to get point relative to transformed coords
func newPointInView(_ point: CGPoint) -> CGPoint {
// get offset from center
let offset = centerOffset(point)
// get transformed point
let transformedPoint = offset.applying(transform)
// make relative to center
return pointRelativeToCenter(transformedPoint)
}
var newTopLeft: CGPoint {
return newPointInView(originalFrame.origin)
}
var newTopRight: CGPoint {
var point = originalFrame.origin
point.x += originalFrame.width
return newPointInView(point)
}
var newBottomLeft: CGPoint {
var point = originalFrame.origin
point.y += originalFrame.height
return newPointInView(point)
}
var newBottomRight: CGPoint {
var point = originalFrame.origin
point.x += originalFrame.width
point.y += originalFrame.height
return newPointInView(point)
}
}
试试这个代码
CGPoint localBeforeTransform = CGPointMake( view.bounds.size.width/2.0f, view.bounds.size.height/2.0f ); // lower left corner
CGPoint localAfterTransform = CGPointApplyAffineTransform(localBeforeTransform, transform);
CGPoint globalAfterTransform = CGPointMake(localAfterTransform.x + view.center.x, localAfterTransform.y + view.center.y);
为什么这么乱?保持简单?在变换之前,x是q rads/度,就像锚周围的其他点一样 本打算解释这一切,但这篇文章中的这一章在更短的上下文中解释了这一点:
我写了这个课程可以帮助我们: TransformedViewFrameCalculator.h
#import <Foundation/Foundation.h>
@interface TransformedViewFrameCalculator : NSObject
@property (nonatomic, strong) UIView *viewToProcess;
- (void)calculateTransformedCornersWithTranslation:(CGPoint)translation
scale:(CGFloat)scale
rotation:(CGFloat)rotation;
@property (nonatomic, readonly) CGPoint transformedTopLeftCorner;
@property (nonatomic, readonly) CGPoint transformedTopRightCorner;
@property (nonatomic, readonly) CGPoint transformedBottomLeftCorner;
@property (nonatomic, readonly) CGPoint transformedBottomRightCorner;
@end
例如,我使用它以以下方式限制容器视图内贴纸的移动/缩放/旋转:
@property (nonatomic, strong) TransformedViewFrameCalculator *transformedFrameCalculator;
所有这些答案都是愚蠢的,这太简单了
CGPoint topLeft = [rotatedView convertPoint:CGPointMake(0, 0) toView:rotatedView.superview];
CGPoint topRight = [rotatedView convertPoint:CGPointMake(rotatedView.bounds.size.width, 0) toView:rotatedView.superview];
CGPoint bottomLeft = [rotatedView convertPoint:CGPointMake(0, rotatedView.bounds.size.height) toView:rotatedView.superview];
CGPoint bottomRight = [rotatedView convertPoint:CGPointMake(rotatedView.bounds.size.width, rotatedView.bounds.size.height) toView:rotatedView.superview];
我对其进行了总结,但并不十分有效:CGFloat-nexting=rte.frame.size.width/2.0;CGFloat反面=rte.frame.size.height/2.0;CGFloat-hipotenuse=sqrtf(功率(相邻,2.0)+功率(相反,2.0));CGFloat theta=acosf((功率因数(hipotenuse,2.0)+功率因数(相邻,2.0)-功率因数(相反,2.0))/(2*hipotenuse*相邻));θ=θ*180/M_π;CGFloat弧度=atan2f(rte.transform.b,rte.transform.a);CGFloat度=弧度*(180/M_-PI);CGFloat width=cosf(θ度)*hipotenuse;CGFloat高度=sinf(θ度)*HIPONEUTE;rightTopNode.center=CGPointMake(rte.center.x+宽度,rte.center.y+高度);嗨,瓦德。我的解释对了。代码中的错误是(这是因为我忘了解释这一部分),因为用于计算宽度和高度的cosf()和sinf()参数必须以弧度为单位。另外,请看我的最新答案。我添加了一个压缩方法,可以为您计算点的坐标。最后,我不知道你为什么要使用atan2f。您提到对视图使用旋转变换。旋转变换函数以弧度为单位进行旋转。您应该使用相同的角度来执行计算。希望这个帮助在某些时候我不能使用旋转变换,我想计算弧度usin
@property (nonatomic, strong) TransformedViewFrameCalculator *transformedFrameCalculator;
self.transformedFrameCalculator = [TransformedViewFrameCalculator new];
self.transformedFrameCalculator.viewToProcess = someView;
- (BOOL)transformedView:(UIView *)view
withTranslation:(CGPoint)translation
scale:(double)scale
rotation:(double)rotation
isFullyInsideValidFrame:(CGRect)validFrame {
[self.transformedFrameCalculator calculateTransformedCornersWithTranslation:translation
scale:scale
BOOL topRightIsInsideValidFrame = CGRectContainsPoint(validFrame, self.transformedFrameCalculator.transformedTopRightCorner);
BOOL topLeftIsInsideValidFrame = CGRectContainsPoint(validFrame, self.transformedFrameCalculator.transformedTopLeftCorner);
BOOL bottomRightIsInsideValidFrame = CGRectContainsPoint(validFrame, self.transformedFrameCalculator.transformedBottomRightCorner);
BOOL bottomLeftIsInsideValidFrame = CGRectContainsPoint(validFrame, self.transformedFrameCalculator.transformedBottomLeftCorner);
return topRightIsInsideValidFrame && topLeftIsInsideValidFrame && bottomRightIsInsideValidFrame && bottomLeftIsInsideValidFrame;
}
CGPoint topLeft = [rotatedView convertPoint:CGPointMake(0, 0) toView:rotatedView.superview];
CGPoint topRight = [rotatedView convertPoint:CGPointMake(rotatedView.bounds.size.width, 0) toView:rotatedView.superview];
CGPoint bottomLeft = [rotatedView convertPoint:CGPointMake(0, rotatedView.bounds.size.height) toView:rotatedView.superview];
CGPoint bottomRight = [rotatedView convertPoint:CGPointMake(rotatedView.bounds.size.width, rotatedView.bounds.size.height) toView:rotatedView.superview];