34

ビューを回転させますCGAffineTransform

[view setTransform:newTransform];

変換が適用された後、フレームの値は同じままですが、このフレームの「回転」または変換された値を見つけるにはどうすればよいですか?


(出典:informit.com

回転したフレーム エッジの正確な座標、つまり a、b、c、d ポイントが必要です。

4

7 に答える 7

55

覚えておくべきことの 1 つは、変換によって座標系が変更されるため、親の「ビュー」と子 (変換された) ビューの間で変換できる必要があることです。また、変換は変換されたオブジェクトの中心を保持しますが、他の座標は保持しません。したがって、中心の観点から物事を計算する必要があります。また、必要なヘルパーがいくつかあります。(次のアプローチのほとんどは、Erica Sadun の本 Core iOS Developer's Cookbook から得ました)。

私は通常、これらを 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];
}

スイフト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)
    }
}
于 2013-10-30T14:47:01.963 に答える
5

以下を使用する必要があります。

CGPoint CGPointApplyAffineTransform (
   CGPoint point,
   CGAffineTransform t
);

特定のポイントを取得するには、ビューの境界と中心を使用してから、ビューの変換を適用して、変換後に新しいポイントを取得します。これは、任意の変換とチェーンをサポートできるため、回転変換専用のコードを追加するよりも優れています。

于 2013-10-27T00:36:41.730 に答える
1

このコードを試してください

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);
于 2013-10-31T16:39:28.813 に答える
0

私は私たちを助けることができるこのクラスを書きました:

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

TransformedViewFrameCalculator.m:

#import "TransformedViewFrameCalculator.h"

@interface TransformedViewFrameCalculator ()

@property (nonatomic, assign) CGRect viewToProcessNotTransformedFrame;
@property (nonatomic, assign) CGPoint viewToProcessNotTransformedCenter;

@end

@implementation TransformedViewFrameCalculator

- (void)setViewToProcess:(UIView *)viewToProcess {
    _viewToProcess = viewToProcess;

    CGAffineTransform t = _viewToProcess.transform;
    _viewToProcess.transform = CGAffineTransformIdentity;

    _viewToProcessNotTransformedFrame = _viewToProcess.frame;
    _viewToProcessNotTransformedCenter = _viewToProcess.center;

    _viewToProcess.transform = t;
}

- (void)calculateTransformedCornersWithTranslation:(CGPoint)translation
                                             scale:(CGFloat)scale
                                          rotation:(CGFloat)rotation {
    double viewWidth = _viewToProcessNotTransformedFrame.size.width * scale;
    double viewHeight = _viewToProcessNotTransformedFrame.size.height * scale;
    CGPoint viewCenter = CGPointMake(_viewToProcessNotTransformedCenter.x + translation.x,
                                     _viewToProcessNotTransformedCenter.y + translation.y);

    _transformedTopLeftCorner = [self calculateCoordinatesForViewPoint:CGPointMake(0, 0)
                                                        fromViewCenter:viewCenter
                                                             viewWidth:viewWidth
                                                            viewHeight:viewHeight
                                                       angleOfRotation:rotation];

    _transformedTopRightCorner = [self calculateCoordinatesForViewPoint:CGPointMake(0, viewHeight)
                                                         fromViewCenter:viewCenter
                                                              viewWidth:viewWidth
                                                             viewHeight:viewHeight
                                                        angleOfRotation:rotation];

    _transformedBottomLeftCorner = [self calculateCoordinatesForViewPoint:CGPointMake(viewWidth, 0)
                                                           fromViewCenter:viewCenter
                                                                viewWidth:viewWidth
                                                               viewHeight:viewHeight
                                                          angleOfRotation:rotation];

    _transformedBottomRightCorner = [self calculateCoordinatesForViewPoint:CGPointMake(viewWidth, viewHeight)
                                                            fromViewCenter:viewCenter
                                                                 viewWidth:viewWidth
                                                                viewHeight:viewHeight
                                                           angleOfRotation:rotation];
}

- (CGPoint)calculateCoordinatesForViewPoint:(CGPoint)viewPoint
                             fromViewCenter:(CGPoint)viewCenter
                                  viewWidth:(CGFloat)viewWidth
                                 viewHeight:(CGFloat)viewHeight
                            angleOfRotation:(CGFloat)angleOfRotation {
    CGPoint centeredViewPoint = CGPointMake(viewPoint.x - viewWidth/2.0, viewPoint.y - viewHeight/2.0);
    CGPoint rotatedCenteredViewPoint = CGPointApplyAffineTransform(centeredViewPoint, CGAffineTransformMakeRotation(angleOfRotation));
    CGPoint rotatedViewPoint = CGPointMake(rotatedCenteredViewPoint.x + viewCenter.x, rotatedCenteredViewPoint.y + viewCenter.y);
    return rotatedViewPoint;
}

たとえば、コンテナー ビュー内のステッカーの移動/スケーリング/回転を次のように制限するために使用します。

@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;
}
于 2016-07-15T16:36:00.123 に答える