如何在应用CGAffineTransformRotate后移动UIImageView?

时间:2011-02-01 06:45:39

标签: iphone uitouch cgaffinetransform

我正在构建一个iPhone应用程序。我有一个UIView包含一组UIImageView子类对象。用户可以通过触摸拖动和旋转图像视图。我在旋转后移动图像视图时遇到了问题。

要旋转图像视图,我应用变换旋转,它可以正常工作。它看起来像这样:

CGAffineTransform trans = self.transform;
self.transform = CGAffineTransformRotate(trans, delta);

当用户尝试通过触摸移动元素时,问题会出现。在touchesBegan:WithEvent:中,我将起始点保存在类变量startLocation中:

- (void) touchesBegan:(NSSet*)touches withEvent:(UIEvent*)event
{   
    // Retrieve the touch point
    CGPoint pt = [[touches anyObject] locationInView:self];
    startLocation = pt;
}

在touchesMoved:withEvent:中,我有以下代码,如果图像视图上没有旋转变换,它就足够好了:

- (void) touchesMoved:(NSSet*)touches withEvent:(UIEvent*)event
{
    CGPoint pt = [[touches anyObject] locationInView:self];
    CGFloat dx = pt.x - startLocation.x;
    CGFloat dy = pt.y - startLocation.y;
    CGPoint newCenter = CGPointMake(self.center.x + dx, self.center.y + dy);
    self.center = newCenter;
}

但是如果在图像视图上存在旋转变换,则图像视图会在每个touchesMoved事件上的屏幕上晃动并很快消失。在调试器中,我观察到pt的值变得怪异。在我看来,我需要改变这一点,我做了,就像这样:

- (void) touchesMoved:(NSSet*)touches withEvent:(UIEvent*)event
{
CGPoint pt = [[touches anyObject] locationInView:self];
if (!CGAffineTransformIsIdentity(self.transform)) {
    pt = CGPointApplyAffineTransform(pt, self.transform);
}

CGFloat dx = pt.x - startLocation.x;
CGFloat dy = pt.y - startLocation.y;
CGPoint newCenter = CGPointMake(self.center.x + dx, self.center.y + dy);
}

这样做效果更好。我现在可以在屏幕上拖动图像。但是第一次移动会导致图像在一个方向或另一个方向上摇晃一次,具体取决于变换中的旋转角度和图像视图的尺寸。

如何在没有初始摇晃的情况下移动图像视图?

为什么我不需要转换startLocation(触摸开始时捕获的点)?

2 个答案:

答案 0 :(得分:1)

- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)_event {
    CGPoint pt = [[touches anyObject] locationInView:self]; 
    startLocation = pt;
} 

- (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)_event {
    CGPoint pt = [[touches anyObject] previousLocationInView:self];
    CGFloat dx = pt.x - startLocation.x;
    CGFloat dy = pt.y - startLocation.y;
    CGPoint newCenter = CGPointMake(self.center.x + dx, self.center.y + dy);
    self.center = newCenter;
}

- (void)setRotation:(float)rotation {
    self.transform = CGAffineTransformRotate(self.transform, degreesToRadians(rotation));
}

答案 1 :(得分:0)

您似乎需要将主要未旋转对象的坐标转换为旋转视图系统。

看看UIView方法“convertPoint:toView:”

  

convertPoint:toView:

     

将接收器坐标系中的点转换为指定视图的点。

     

- (CGPoint)convertPoint:(CGPoint)指向View:(UIView *)视图

     

参数

     

     

接收器的本地坐标系(边界)中指定的点。

     

查看

     

要转换其坐标系点的视图。如果view为nil,则此方法将转换为窗口基坐标。否则,视图和接收者都必须属于同一个UIWindow对象。

     

返回值

     

转换为视图坐标系的点。

更新

回应评论:

你必须得到手指触摸的“真实”坐标(在非旋转系统中),然后当手指移动时,你总是在主非旋转视图中有新的坐标:它们就是你的意思必须转换您正在移动的视图的旋转视图父级。

  • 如果 A 是主视图 320x480 像素
  • B 是以 A 为中心的子视图 320x480 像素,
  • C B 中的子视图 170,240 + 10,+ 0 的屏幕中心)
  • 并顺时针旋转 90 B
  • 然后 C 仍然在 B
  • 170,240

但你在屏幕上的 160,250 中看到它,

如果现在用户想要向右移动 +20 ,用户会在屏幕坐标中移动手指 +20 ,而不是 B 查看坐标, 所以用户希望在屏幕的 180,250 中看到它, 这意味着您需要在 B 坐标系中转换此点 ...

所以它更容易一些,你只需要在用户移动手指时获取手指的屏幕坐标,然后将其转换为旋转视图坐标( B )......