如何使用子视图调整UIView的大小

时间:2014-01-09 22:34:17

标签: ios iphone objective-c uigesturerecognizer

我的目标是使用句柄 - 其子视图调整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;
  }
}

请注意,我使用中心边界属性,因为当我的视图应用了变换时,frame NOT 可靠。

但是,我的要求是在任何方向调整视图大小 - 不仅按照代码的比例调整大小。问题是我找不到正确的方法或方法,这个句柄可能会调整其超视图的边界(宽度或高度),因此当手指拖动它时它总是粘在角落上。

如果我更容易理解我的意思,这是我的project

更新解决方案正如以下答案所建议的那样效果非常好但是一旦应用了转换(例如在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);
}

3 个答案:

答案 0 :(得分: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。

答案 1 :(得分: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];
    }}
}

答案 2 :(得分:1)

我不会用子视图来控制它。将变换应用于外部视图时会变得混乱。 只需将两个视图添加到ViewController,并使用一些代码将它们连接起来。 我已修改项目,找到test-001 at GitHub

ViewController 代码可以为空。

您要转换的视图 TransformableView 需要一个scale属性,以及一个应用它的方法(如果您还要添加其他转换)。

@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中设置类,并连接 IBAction IBOutletDraggableView

enter image description here