旋转后翻译UIView

时间:2014-02-22 05:24:02

标签: ios objective-c rotation translation cgaffinetransform

我正在尝试使用来自用户的触摸来翻译已旋转和/或缩放的UIView。我尝试用用户输入翻译它:

- (void)handleObjectMove:(UIPanGestureRecognizer *)recognizer
{
    static CGPoint lastPoint;
    UIView *moveView = [recognizer view];
    CGPoint newCoord = [recognizer locationInView:playArea];

    // Check if this is the first touch
    if( [recognizer state]==UIGestureRecognizerStateBegan )
    {
        // Store the initial touch so when we change positions we do not snap
        lastPoint = newCoord;
    }

    // Create the frame offsets to use our finger position in the view.
    float dX = newCoord.x;
    float dY = newCoord.y;

    dX-=lastPoint.x;
    dY-=lastPoint.y;

    // Figure out the translation based on how we are scaled
    CGAffineTransform transform = [moveView transform];
    CGFloat xScale = transform.a;
    CGFloat yScale = transform.d;

    dX/=xScale;
    dY/=yScale;

    lastPoint = newCoord;

    [moveView setTransform:CGAffineTransformTranslate( transform, dX, dY )];

    [recognizer setTranslation:CGPointZero inView:playArea];
}

但是当我触摸并移动视图时,它会以各种奇怪的方式进行翻译。我可以使用旋转值来应用某种公式来正确翻译吗?

4 个答案:

答案 0 :(得分:2)

我发现必须使用最少量数学的最佳解决方案是分别存储原始平移,旋转和缩放值,并在更改时重做变换。我的解决方案是使用以下属性为UIView创建子类:

@property (nonatomic) CGPoint translation;
@property (nonatomic) CGFloat rotation;
@property (nonatomic) CGPoint scaling;

以下功能:

- (void)rotationDelta:(CGFloat)delta
{
    [self setRotation:[self rotation]+delta];
}

- (void)scalingDelta:(CGPoint)delta
{
    [self setScaling:
     (CGPoint){ [self scaling].x*delta.x, [self scaling].y*delta.y }];
}

- (void)translationDelta:(CGPoint)delta
{
    [self setTranslation:
     (CGPoint){ [self translation].x+delta.x, [self translation].y+delta.y }];
}

- (void)transformMe
{
    // Start with the translation
    CGAffineTransform transform = CGAffineTransformMakeTranslation( [self translation].x, [self translation].y );
    // Apply scaling
    transform = CGAffineTransformScale( transform, [self scaling].x, [self scaling].y );
    // Apply rotation
    transform = CGAffineTransformRotate( transform, [self rotation] );

    [self setTransform:transform];
}

- (void)setScaling:(CGPoint)newScaling
{
    scaling = newScaling;
    [self transformMe];
}

- (void)setRotation:(CGFloat)newRotation
{
    rotation = newRotation;
    [self transformMe];
}

- (void)setTranslation:(CGPoint)newTranslation
{
    translation = newTranslation;
    [self transformMe];
}

并在处理程序中使用以下内容:

- (void)handleObjectPinch:(UIPinchGestureRecognizer *)recognizer
{
    if( [recognizer state] == UIGestureRecognizerStateEnded
        || [recognizer state] == UIGestureRecognizerStateChanged )
    {
        // Get my stuff
        if( !selectedView )
            return;

        SelectableImageView *view = selectedView;

        CGFloat scaleDelta = [recognizer scale];
        [view scalingDelta:(CGPoint){ scaleDelta, scaleDelta }];

        [recognizer setScale:1.0];
    }
}

- (void)handleObjectMove:(UIPanGestureRecognizer *)recognizer
{
    static CGPoint lastPoint;
    SelectableImageView *moveView = (SelectableImageView *)[recognizer view];
    CGPoint newCoord = [recognizer locationInView:playArea];

    // Check if this is the first touch
    if( [recognizer state]==UIGestureRecognizerStateBegan )
    {
        // Store the initial touch so when we change positions we do not snap
        lastPoint = newCoord;
    }

    // Create the frame offsets to use our finger position in the view.
    float dX = newCoord.x;
    float dY = newCoord.y;

    dX-=lastPoint.x;
    dY-=lastPoint.y;
    lastPoint = newCoord;

    [moveView translationDelta:(CGPoint){ dX, dY }];

    [recognizer setTranslation:CGPointZero inView:playArea];
}

- (void)handleRotation:(UIRotationGestureRecognizer *)recognizer
{
    if( [recognizer state] == UIGestureRecognizerStateEnded
       || [recognizer state] == UIGestureRecognizerStateChanged )
    {
        if( !selectedView )
            return;

        SelectableImageView *view = selectedView;

        CGFloat rotation = [recognizer rotation];
        [view rotationDelta:rotation];

        [recognizer setRotation:0.0];
    }
}

答案 1 :(得分:0)

尝试直接更改moveView.center而不是Set(x,y)或“CGAffineTransformTranslate”

答案 2 :(得分:0)

这是可转换 UIView 的 Swift 4/5 版本

class TransformableImageView: UIView{

var translation:CGPoint = CGPoint(x:0,y:0)

var scale:CGPoint = CGPoint(x:1, y:1)

var rotation:CGFloat = 0


override init (frame : CGRect) {
   super.init(frame: frame)
}


required init?(coder aDecoder: NSCoder) {
    fatalError("init(coder:) has not been implemented")
}

func rotationDelta(delta:CGFloat) {
    rotation = rotation + delta
}

func scaleDelta(delta:CGPoint){
    scale = CGPoint(x: scale.x*delta.x, y: scale.y * delta.y)
}

func translationDelta(delta:CGPoint){
    translation = CGPoint(x: translation.x+delta.x, y: translation.y + delta.y)
}



func transform(){
    self.transform = CGAffineTransform.identity.translatedBy(x: translation.x, y: translation.y).scaledBy(x: scale.x, y: scale.y ).rotated(by: rotation )
}

}

答案 3 :(得分:-1)

我离开这里,因为我也遇到了同样的问题。以下是如何在swift 2中执行此操作:

将您的俯视图作为子视图添加到底部视图中:

self.view.addSubview(topView)

然后添加PanGesture识别器以继续触摸:

//Add PanGestureRecognizer to move
    let panMoveGesture = UIPanGestureRecognizer(target: self, action: #selector(YourViewController.moveViewPanGesture(_:)))
    topView.addGestureRecognizer(panMoveGesture)

移动的功能:

//Move function
func moveViewPanGesture(recognizer:UIPanGestureRecognizer)
{
    if recognizer.state == .Changed {
        var center = recognizer.view!.center
        let translation = recognizer.translationInView(recognizer.view?.superview)
        center = CGPoint(x:center.x + translation.x,
                             y:center.y + translation.y)
        recognizer.view!.center = center
        recognizer.setTranslation(CGPoint.zero, inView: recognizer.view)
    }
}

基本上,您需要根据底视图翻译视图,而视图是超视图本身。像这样:recognizer.view?.superview 或者,如果您还旋转底部视图,则可以添加一个不会有任何转换的视图,并将底部视图添加到不转换视图(非常底部视图),并将顶视图相应地添加到底视图作为子视图。然后,您应该根据最底层视图翻译您的顶视图。