使用 Transform 旋转时调整 UIView 的大小

Posted

技术标签:

【中文标题】使用 Transform 旋转时调整 UIView 的大小【英文标题】:Resize UIView While It Is Rotated with Transform 【发布时间】:2013-11-19 22:19:33 【问题描述】:

当我的UIView 使用变换属性 (CGAffineTransformMakeRotation) 旋转时,我需要拖动它的一个角,比如右下角,以调整它的大小。在用户拖动角的过程中,视图的角必须跟随用户的手指并通过增加 2 个边来调整框的大小(右下角拖动的右下角大小)。

当你可以在盒子没有变形的情况下使用框架和触摸位置时,调整UIView的大小并不难。例如,我会记住初始帧和触摸在UIPanGestureRecognizer handler 附加到 StateBegan 上的这个可调整大小的视图,并且在 StateChanged 上我会计算触摸点 X, Y 与初始触摸的差异并将这些值添加到初始帧宽度和高度。

但是,当应用变换时,框架对于旋转的UIView 是可靠的。因此我只能依靠boundscenter。我创建了这段代码,但它几乎可以工作:我只能在所有 4 个方向上按比例放大视图,而不是一个。

- (void)handleResizeGesture:(UIPanGestureRecognizer *)recognizer 
    CGPoint touchLocation = [recognizer locationInView:self.superview];
    CGPoint center = self.center;

    switch (recognizer.state) 
        case UIGestureRecognizerStateBegan: 
            deltaAngle = atan2f(touchLocation.y - center.y, touchLocation.x - center.x) - CGAffineTransformGetAngle(self.transform);
            initialBounds = self.bounds;
            initialDistance = CGPointGetDistance(center, touchLocation);
            initialLocation = touchLocation;
            if ([self.delegate respondsToSelector:@selector(stickerViewDidBeginRotating:)]) 
                [self.delegate stickerViewDidBeginRotating:self];
            
            break;
        

        case UIGestureRecognizerStateChanged: 

            CGFloat scale = CGPointGetDistance(center, touchLocation)/initialDistance;
            CGFloat minimumScale = self.minimumSize/MIN(initialBounds.size.width, initialBounds.size.height);
            scale = MAX(scale, minimumScale);
            CGRect scaledBounds = CGRectScale(initialBounds, scale, scale);
            self.bounds = scaledBounds;

            [self setNeedsDisplay];

            if ([self.delegate respondsToSelector:@selector(stickerViewDidChangeRotating:)]) 
                [self.delegate stickerViewDidChangeRotating:self];
            
            break;
        

        case UIGestureRecognizerStateEnded:
            if ([self.delegate respondsToSelector:@selector(stickerViewDidEndRotating:)]) 
                [self.delegate stickerViewDidEndRotating:self];
            
            break;

        default:
            break;
    

下图显示了具有已知值(A、B、x、y、N、M、N-M 距离)的旋转视图:

【问题讨论】:

我认为您正在寻找的是图层的anchorPoint 属性。 【参考方案1】:

好问题。我刚刚创建了使用类似东西的类。在我的课堂上,你可以改变 UIViewA 的比例,它会改变 UIViewB 的比例,同时保持相同的比例。

检查左上角的白色小方块:

可以在这里找到课程:https://github.com/sSegev/SSUIViewMiniMe

你问的有点不同。我正在更改正方形的总大小,而您只想根据用户拖动它的距离来更改相对于其中一个角的大小。

因为你不能在按钮动画时点击它(嗯,你可以,但动画只是眼睛糖果,视图已经处于最终状态)我使用了 CABasicAnimation,这使它更容易。

- (void)viewDidAppear:(BOOL)animated

        [super viewDidAppear:animated];
        //Rotate the UIView            
    if ([_myRedView.layer animationForKey:@"SpinAnimation"] == nil)
        
            CABasicAnimation* animation = [CABasicAnimation animationWithKeyPath:@"transform.rotation.z"];
            animation.fromValue = [NSNumber numberWithFloat:0.0f];
            animation.toValue = [NSNumber numberWithFloat: 2*M_PI];
            animation.duration = 50.0f;
            animation.repeatCount = INFINITY;
            [self.myRedView.layer addAnimation:animation forKey:@"SpinAnimation"];
        


 // That's the main chunk of code:

- (void)dragBegan:(UIControl *)c withEvent:ev

    UITouch *touch = [[ev allTouches] anyObject];
    CGPoint touchPoint = [touch locationInView:_myRedView];
    NSLog(@"Touch x : %f y : %f", touchPoint.x, touchPoint.y);
    if(_myRedView.width/2<touchPoint.x && _myRedView.height/2<touchPoint.y) //Checks for right bottom corner
        
            _myRedView.width =touchPoint.x;
            _myRedView.height = touchPoint.y;
            dragButton.frame = CGRectMake(0, 0, _myRedView.width, _myRedView.height);
        

我确定需要进行一些调整,但现在看起来像这样:

*

仅仅 6 行代码就很酷了哈?

【讨论】:

这不是我要找的。我将归结为我所需要的:找到知道斜边的导管 A 和 B 以及直角的一点 (x,y)。 我不明白。你推广了你的项目,但没有回答我的问题,并且给了你一半的赏金。这是 SO 的常见做法吗? 我不明白。我花了自己的时间写了一个详细的答案,而你和你的行为就像我欠你的东西一样忘恩负义的评论。这是地球上常见的做法吗?是的 莎:抱歉给我带来了不愉快的回应。是的,感谢您的时间和有趣的解决方案。它应该在这里。如果我需要其他答案,我可以重新发布我的问题。【参考方案2】:

不要尝试更改框架,而是根据您的手势调整视图的scale 属性。这应该会在不干扰旋转的情况下正确调整视图大小。

【讨论】:

谢谢,但我根本没有改变框架。我改变了中心的边界,因为框架不适用于转换后的视图。此外,缩放会影响我不想要的子视图。我想要的只是根据用户拖动的距离来计算 WIDTH 和 HEIGHT。知道我可以正确更改边界并修改中心。 在 CGAffineTransform 之后,不再定义 UIView 的属性框架。文档说“警告:如果转换属性不是身份转换,则此属性的值未定义,因此应被忽略。” 好的。然后尝试您的手势方法:撤消旋转,调整大小,然后重新应用旋转。 虽然这是有道理的,但我却被困在新边界的正确计算上。我知道中心点、手指触摸位置和初始边界,但如何使用这些已知值得出新边界是我的问题,因为视图现在已旋转,我不知道增加/减少宽度/高度多少。 有道理,试试这个:将手势识别器放在调整大小视图的超级视图中。在手势方法中,执行命中测试以查看手势是否正在触摸调整大小的视图。获取该调整大小的视图并根据手势在超级视图中的移动进行调整大小计算,而不是调整大小。【参考方案3】:

将您的视图嵌入到容器视图中。然后变换容器,保持可拖动视图不变。使用与未旋转视图相同的逻辑。

【讨论】:

谢谢,但我的问题是如何在知道新接触点的情况下计算旋转视图的新边界。很抱歉,如果不是很清楚。

以上是关于使用 Transform 旋转时调整 UIView 的大小的主要内容,如果未能解决你的问题,请参考以下文章

如何将 UIView 调整为横向?

在 iphone 应用程序中使用 UIRotationGestureRecognizer 旋转时调整图像大小

如何在方向更改时调整多个标签的大小以自动适应 UIView 内部

UIView drawRect 未在自动旋转时调用

UIPageViewController 没有在旋转时调整其子视图控制器的大小

如何在移动时调整 UIView 的大小,就像 SnapGuide 一样?