2014-01-09 4 views
3

Моя цель - изменить размер UIView с помощью дескриптора. Я получил мой проект прекрасно работает для достижения этой цели: ручка имеет PanGestureRecognizer и способ его обработчик изменяет представление (родительский), используя следующий метод:Как изменить размер UIView с Subview

-(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; 
    } 
} 

Пожалуйста, обратите внимание, что я использую центр и границы свойства потому что кадр 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); 
} 
+0

Зачем изменять размер с подвью? Было бы намного сложнее, если бы вы включили представление цели и обработчика в представление. Я бы изменил проект, который вы отправили, если вы в порядке с этим решением. – Geri

+0

Почему вы имеете дело с любой тригонометрией здесь? – Geri

+0

Как еще рассчитать точки расстояния? – Vad

ответ

2

You устанавливают тот же параметр масштаба в вашем вызове 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.

+0

Спасибо. Позвольте мне попробовать - это может быть очень близко к тому, что я ищу. – Vad

+0

Это очень близко. Он перескакивает при первом перетаскивании, сводя к минимуму представление контейнера, но затем работает так, как ожидалось. Я буду играть с этим. Благодарю. – Vad

+0

Использовать initialDistanceX и initialDistanceY. Это должно решить прыжок при первом перетаскивании. – Saikat

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]; 
    }} 
} 
+0

Почему щепотка распознавания? это, кажется, усложняет это больше. – Vad

1

я бы не контролировать его с подвид. Это становится беспорядочным, когда вы применяете преобразование к внешнему виду. Просто добавьте два вида в ViewController и подключите их с помощью некоторого кода. Я изменил проект, нахожу 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, и подключить IBAction и IBOutlet из DraggableView.

enter image description here

+0

Спасибо, но снова ... Для меня нужно преобразовать супер-представление, а управление перетаскиваемым углом сложнее с этим подходом. – Vad

+0

Я бы обернул эти представления в объект, похожий на 'ResizableViewGroup', поэтому вам не понадобится« обратная манипуляция »надстройкой. Это останется простой и прямой, без причудливых обратных обходных решений. – Geri

Смежные вопросы