如何调整带有子视图的UIView的大小

3

我的目标是使用手柄(子视图)调整UIView的大小。我已经完美地完成了该项目以实现此目标:手柄具有PanGestureRecognizer,其处理程序方法使用以下方法调整视图(父级)的大小:

-(IBAction)handleResizeGesture:(UIPanGestureRecognizer *)recognizer {

  CGPoint touchLocation = [recognizer locationInView:container.superview];
  CGPoint center = container.center;

  switch (recognizer.state) {
    case UIGestureRecognizerStateBegan: {
        deltaAngle = atan2f(touchLocation.y - center.y, touchLocation.x - center.x) - 
                            CGAffineTransformGetAngle(container.transform);
        initialBounds = container.bounds;
        initialDistance = CGPointGetDistance(center, touchLocation);
        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);
        container.bounds = scaledBounds;

        [container setNeedsDisplay];

        break;
    }

    case UIGestureRecognizerStateEnded:

        break;

    default:
        break;
  }
}

请注意,我使用 centerbounds 属性,因为应用变换到我的视图时,frame 是不可靠的。
然而,我的要求是以任何方向调整视图的大小,而不仅仅是代码中按比例调整视图大小。问题在于,我无法找到正确的方法或途径来处理如何调整其父视图的边界(宽度或高度),以便手指拖动它时始终粘着角落。
如果您想更好地理解我的意思,可以查看我的项目
更新的解决方案很好,但是一旦应用了变换(例如,在viewDidLoad中我使用 container.transform = CGAffineTransformMakeRotation(90);),它就失效了。
    case UIGestureRecognizerStateBegan: {
        initialBounds = container.bounds;
        initialDistance = CGPointGetDistance(center, touchLocation);
        initialDistanceX = CGPointGetDistanceX(center, touchLocation);
        initialDistanceY = CGPointGetDistanceY(center, touchLocation);
        break;
    }

    case UIGestureRecognizerStateChanged: {

        CGFloat scaleX = abs(center.x-touchLocation.x)/initialDistanceX;
        CGFloat scaleY = abs(center.y-touchLocation.y)/initialDistanceY;
        CGFloat minimumScale = self.minimumSize/MIN(initialBounds.size.width, initialBounds.size.height);
        scaleX = MAX(scaleX, minimumScale);
        scaleY = MAX(scaleY, minimumScale);
        CGRect scaledBounds = CGRectScale(initialBounds, scaleX, scaleY);
        container.bounds = scaledBounds;
        [container setNeedsDisplay];

        break;
    }

何处

CG_INLINE CGFloat CGPointGetDistanceX(CGPoint point1, CGPoint point2) {
  return (point2.x - point1.x);
}
CG_INLINE CGFloat CGPointGetDistanceY(CGPoint point1, CGPoint point2) {
  return (point2.y - point1.y);
}

为什么要使用subview调整大小?如果将目标视图和处理程序视图都包裹到一个视图中,则会简单得多。如果您同意这种解决方案,我可以修改您发送的项目。 - Geri Borbás
你为什么要在这里处理任何三角学? - Geri Borbás
如何计算点之间的距离? - Vad
3个回答

2

你在调用CGRectScale(initialBounds, scale, scale)时设置了相同的比例参数,尝试使用以下代码:

case UIGestureRecognizerStateChanged: {
            CGFloat scaleX = abs(center.x-touchLocation.x)/initialDistance;
            CGFloat scaleY = abs(center.y-touchLocation.y)/initialDistance;
            CGFloat minimumScale = self.minimumSize/MIN(initialBounds.size.width, initialBounds.size.height);
            scaleX = MAX(scaleX, minimumScale);
            scaleY = MAX(scaleY, minimumScale);
            CGRect scaledBounds = CGRectScale(initialBounds, scaleX, scaleY);
            container.bounds = scaledBounds;

            [container setNeedsDisplay];

            break;

您可以考虑存储initialDistanceX和initialDistanceY。

使用initialDistanceX和initialDistanceY。这应该解决第一次拖动时的跳跃问题。 - Saikat
谢谢。我尝试了这个代码:CG_INLINE CGFloat CGPointGetDistanceX(CGPoint point1,CGPoint point2){return (point2.x - point1.x);} 看起来运行良好。我会进行更多测试并确认后再回来。 - Vad
一个问题:一旦应用了变换,它就不能完美地工作 - 当视图倒置时,initialDistanceY似乎处于最小值。 - Vad
我开始了悬赏,以改进这个答案,使其能够与转换后的视图一起使用。谢谢。 - Vad
Saikat,你的解决方案对我来说已经有90%的效果了。调整代码有什么进展吗? - Vad
显示剩余2条评论

1
我不会使用子视图来进行控制,这会在对外部视图应用变换时变得混乱。 只需向ViewController添加两个view,并将它们与一些代码连接起来即可。 我已经修改了项目,请查看 test-001 at GitHub
这种情况下,ViewController的代码可以为空。
您想要进行变换的视图TransformableView需要具有缩放属性和一个应用它的方法(如果您还想添加其他变换)。
@interface TransformableView : UIView

@property (nonatomic) CGSize scale;
-(void)applyTransforms;

@end

@implementation TransformableView

-(void)applyTransforms
{
    // Do whatever additional transform you want (e.g. concat additional rotations / mirroring to the transform).
    self.transform =  CGAffineTransformMakeScale(self.scale.width, self.scale.height);
}

@end

DraggableCorner可以处理其余部分(需要一些基本数学知译)。
@class TransformableView;
@interface DraggableCorner : UIView

@property (nonatomic, weak) IBOutlet TransformableView *targetView; // Hook up in IB.
-(IBAction)panGestureRecognized:(UIPanGestureRecognizer*) recognizer;

@end

CG_INLINE CGPoint offsetOfPoints(CGPoint point1, CGPoint point2)
{ return (CGPoint){point1.x - point2.x, point1.y -point2.y}; }

CG_INLINE CGPoint addPoints(CGPoint point1, CGPoint point2)
{ return (CGPoint){point1.x + point2.x, point1.y + point2.y}; }


@interface DraggableCorner ()
@property (nonatomic) CGPoint touchOffset;
@end


@implementation DraggableCorner


-(IBAction)panGestureRecognized:(UIPanGestureRecognizer*) recognizer
{
    // Location in superview.
    CGPoint touchLocation = [recognizer locationInView:self.superview];

    // Began.
    if (recognizer.state == UIGestureRecognizerStateBegan)
    {
        // Finger distance from handler.
        self.touchOffset = offsetOfPoints(self.center, touchLocation);
    }

    // Moved.
    if (recognizer.state == UIGestureRecognizerStateChanged)
    {
        // Drag.
        self.center = addPoints(touchLocation, self.touchOffset);

        // Desired size.
        CGPoint distanceFromTargetCenter = offsetOfPoints(self.center, self.targetView.center);
        CGSize desiredTargetSize = (CGSize){distanceFromTargetCenter.x * 2.0, distanceFromTargetCenter.y * 2.0};

        // -----
        // You can put limitations here, simply clamp `desiredTargetSize` to some value.
        // -----

        // Scale needed for desired size.
        CGSize targetSize = self.targetView.bounds.size;
        CGSize targetRatio = (CGSize){desiredTargetSize.width / targetSize.width, desiredTargetSize.height / targetSize.height};

        // Apply.
        self.targetView.scale = targetRatio;
        [self.targetView applyTransforms];
    }
}

在IB中设置类,并连接DraggableViewIBActionIBOutlet

enter image description here


谢谢,但是...超级视图必须为我转换,并且使用这种方法更难管理可拖动的角落。 - Vad
我会将这些视图封装到一个对象中,例如 ResizableViewGroup,这样你就不需要“反向操作”父视图了。这样做会保持简单和直接,而不需要奇怪的后向解决方法。 - Geri Borbás

1
使用`UIPinchGestureRecognizer`和`UIPanGestureRecognizer`。
试一下这段代码。
    //--Create and configure the pinch gesture
    UIPinchGestureRecognizer *pinchGestureRecognizer = [[UIPinchGestureRecognizer alloc] initWithTarget:self action:@selector(pinchGestureDetected:)];
    [pinchGestureRecognizer setDelegate:self];
    [container.superview addGestureRecognizer:pinchGestureRecognizer];

    //--Create and configure the pan gesture
    UIPanGestureRecognizer *panGestureRecognizer = [[UIPanGestureRecognizer alloc] initWithTarget:self action:@selector(panGestureDetected:)];
    [panGestureRecognizer setDelegate:self];
    [container.superview addGestureRecognizer:panGestureRecognizer];

对于 UIPinchGestureRecognizer
- (void)pinchGestureDetected:(UIPinchGestureRecognizer *)recognizer
{

    UIGestureRecognizerState state = [recognizer state];

    if (state == UIGestureRecognizerStateBegan || state == UIGestureRecognizerStateChanged)
    {
        CGFloat scale = [recognizer scale];
        [recognizer.view setTransform:CGAffineTransformScale(recognizer.view.transform, scale, scale)];
        [recognizer setScale:1.0];
        panGesture = YES;
    }
}

对于UIPanGestureRecognizer:

- (void)panGestureDetected:(UIPanGestureRecognizer *)recognizer
{
    UIGestureRecognizerState state = [recognizer state];
    if (panGesture==YES)
    {
    if (state == UIGestureRecognizerStateBegan || state == UIGestureRecognizerStateChanged)
    {
        CGPoint translation = [recognizer translationInView:recognizer.view];
        [recognizer.view setTransform:CGAffineTransformTranslate(recognizer.view.transform, translation.x, translation.y)];
        [recognizer setTranslation:CGPointZero inView:recognizer.view];
    }}
}

为什么要使用捏合手势识别器?它似乎会让事情变得更加复杂。 - Vad

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接