如何在应用CGAffineTransformRotate后移动UIImageView?

ric*_*sun 5 iphone uitouch cgaffinetransform

我正在构建一个iPhone应用程序.我有一个UIView包含一组UIImageView子类对象.用户可以通过触摸拖动和旋转图像视图.旋转后我无法移动图像视图.

要旋转图像视图,我应用变换旋转,这很好.它看起来像这样:

CGAffineTransform trans = self.transform;
self.transform = CGAffineTransformRotate(trans, delta);
Run Code Online (Sandbox Code Playgroud)

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

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

在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;
}
Run Code Online (Sandbox Code Playgroud)

但是如果在图像视图上存在旋转变换,则图像视图会在每个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);
}
Run Code Online (Sandbox Code Playgroud)

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

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

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

mer*_*nix 0

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

\n\n

看一下 UIView 方法“convertPoint:toView:”

\n\n
\n

将点转换为视图:

\n\n

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

\n\n

- (CGPoint)convertPoint:(CGPoint)指向View:(UIView *)view

\n\n

参数

\n\n

观点

\n\n

在接收器的局部坐标系(边界)中指定的点。

\n\n

看法

\n\n

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

\n\n

返回值

\n\n

该点转换为视图坐标系。

\n
\n\n

更新:

\n\n

回应评论:

\n\n

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

\n\n
    \n
  • 如果A是 mainView 320x480像素
  • \n
  • B是一个以A为中心的 320x480 像素的视图
  • \n
  • C是B中位置170,240 屏幕中心的+10,+0 )处的子视图
  • \n
  • 然后将B顺时针旋转90
  • \n
  • 那么C仍然在B的170,240
  • \n
\n\n

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

\n\n

如果现在用户想要将其向右移动+20 ,则用户将手指在屏幕坐标中移动+20 ,而不是在B视图坐标中,\n因此用户希望在屏幕的180,250中看到它,\n意味着你需要在B坐标系中转换这个点......

\n\n

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

\n