使用UIPinchGestureRecognizer在缩放方向上缩放视图

Sco*_*ott 2 scaling scale ios uipinchgesturerecognizer

我需要一个可以在x,y或两个方向上缩放的Pinch识别器,具体取决于收缩的方向.我在这里查看了许多其他问题,他们只有部分答案.这是我使用自定义UIPinchGestureRecognizer的完整解决方案.

Sco*_*ott 10

我创建了一个UIPinchGestureRecognizer的自定义版本.它使用两个手指之间的直线斜率来确定刻度的方向.它有3种类型:垂直; 水平; 和组合(对角线).请在底部查看我的笔记.

-(void) scaleTheView:(UIPinchGestureRecognizer *)pinchRecognizer
{
if ([pinchRecognizer state] == UIGestureRecognizerStateBegan || [pinchRecognizer state] == UIGestureRecognizerStateChanged) {

if ([pinchRecognizer numberOfTouches] > 1) {

    UIView *theView = [pinchRecognizer view];

    CGPoint locationOne = [pinchRecognizer locationOfTouch:0 inView:theView];
    CGPoint locationTwo = [pinchRecognizer locationOfTouch:1 inView:theView];
        NSLog(@"touch ONE  = %f, %f", locationOne.x, locationOne.y);
        NSLog(@"touch TWO  = %f, %f", locationTwo.x, locationTwo.y);
    [scalableView setBackgroundColor:[UIColor redColor]];

    if (locationOne.x == locationTwo.x) {
            // perfect vertical line
            // not likely, but to avoid dividing by 0 in the slope equation
        theSlope = 1000.0;
    }else if (locationOne.y == locationTwo.y) {
            // perfect horz line
            // not likely, but to avoid any problems in the slope equation
        theSlope = 0.0;
    }else {
        theSlope = (locationTwo.y - locationOne.y)/(locationTwo.x - locationOne.x);
    }

    double abSlope = ABS(theSlope);

    if (abSlope < 0.5) {
                //  Horizontal pinch - scale in the X
        [arrows setImage:[UIImage imageNamed:@"HorzArrows.png"]];
        arrows.hidden = FALSE;
                // tranform.a  = X-axis
            NSLog(@"transform.A = %f", scalableView.transform.a);
                // tranform.d  = Y-axis
            NSLog(@"transform.D = %f", scalableView.transform.d);

                //  if hit scale limit along X-axis then stop scale and show Blocked image
        if (((pinchRecognizer.scale > 1.0) && (scalableView.transform.a >= 2.0)) || ((pinchRecognizer.scale < 1.0) && (scalableView.transform.a <= 0.1))) {
            blocked.hidden = FALSE;
            arrows.hidden = TRUE;
        } else {
                    // scale along X-axis
            scalableView.transform = CGAffineTransformScale(scalableView.transform, pinchRecognizer.scale, 1.0);
            pinchRecognizer.scale = 1.0;
            blocked.hidden = TRUE;
            arrows.hidden = FALSE;
        }
    }else if (abSlope > 1.7) {
                // Vertical pinch - scale in the Y
        [arrows setImage:[UIImage imageNamed:@"VerticalArrows.png"]];
        arrows.hidden = FALSE;
            NSLog(@"transform.A = %f", scalableView.transform.a);
            NSLog(@"transform.D = %f", scalableView.transform.d);

                //  if hit scale limit along Y-axis then don't scale and show Blocked image
        if (((pinchRecognizer.scale > 1.0) && (scalableView.transform.d >= 2.0)) || ((pinchRecognizer.scale < 1.0) && (scalableView.transform.d <= 0.1))) {
            blocked.hidden = FALSE;
            arrows.hidden = TRUE;
        } else {
                    // scale along Y-axis
            scalableView.transform = CGAffineTransformScale(scalableView.transform, 1.0, pinchRecognizer.scale);
            pinchRecognizer.scale = 1.0;
            blocked.hidden = TRUE;
            arrows.hidden = FALSE;
        }
    } else {
                // Diagonal pinch - scale in both directions
        [arrows setImage:[UIImage imageNamed:@"CrossArrows.png"]];
        blocked.hidden = TRUE;
        arrows.hidden = FALSE;

            NSLog(@"transform.A = %f", scalableView.transform.a);
            NSLog(@"transform.D = %f", scalableView.transform.d);

                // if we have hit any limit don't allow scaling
        if ((((pinchRecognizer.scale > 1.0) && (scalableView.transform.a >= 2.0)) || ((pinchRecognizer.scale < 1.0) && (scalableView.transform.a <= 0.1))) || (((pinchRecognizer.scale > 1.0) && (scalableView.transform.d >= 2.0)) || ((pinchRecognizer.scale < 1.0) && (scalableView.transform.d <= 0.1)))) {
            blocked.hidden = FALSE;
            arrows.hidden = TRUE;
        } else {
                    // scale in both directions
            scalableView.transform = CGAffineTransformScale(scalableView.transform, pinchRecognizer.scale, pinchRecognizer.scale);
            pinchRecognizer.scale = 1.0;
            blocked.hidden = TRUE;
            arrows.hidden = FALSE;
        }
    }  // else for diagonal pinch
}  // if numberOfTouches
}  // StateBegan if

if ([pinchRecognizer state] == UIGestureRecognizerStateEnded || [pinchRecognizer state] == UIGestureRecognizerStateCancelled) {
NSLog(@"StateEnded StateCancelled");
[scalableView setBackgroundColor:[UIColor whiteColor]];
arrows.hidden = TRUE;
blocked.hidden = TRUE;
}
}
Run Code Online (Sandbox Code Playgroud)

请记住将协议添加到视图控制器头文件中:

@interface WhiteViewController : UIViewController <UIGestureRecognizerDelegate>
{
IBOutlet UIView *scalableView;
IBOutlet UIView *mainView;
IBOutlet UIImageView *arrows;
IBOutlet UIImageView *blocked;
}
@property (strong, nonatomic) IBOutlet UIView *scalableView;
@property (strong, nonatomic) IBOutlet UIView *mainView;
@property (strong, nonatomic)IBOutlet UIImageView *arrows;
@property (strong, nonatomic)IBOutlet UIImageView *blocked;

-(void) scaleTheView:(UIPinchGestureRecognizer *)pinchRecognizer;
@end
Run Code Online (Sandbox Code Playgroud)

并在viewDidLoad中添加识别器:

- (void)viewDidLoad
{ 
UIPinchGestureRecognizer *pinchGesture = [[UIPinchGestureRecognizer alloc] initWithTarget:self action:@selector(scaleTheView:)];
[pinchGesture setDelegate:self];
[mainView addGestureRecognizer:pinchGesture];
arrows.hidden = TRUE;
blocked.hidden = TRUE;
[scalableView setBackgroundColor:[UIColor whiteColor]];
}
Run Code Online (Sandbox Code Playgroud)

这被设置为使用主视图捕获捏; 并操纵第二个视图.这样,您可以在视图变小时进行缩放.您可以更改它以直接对可伸缩视图做出反应.

限制:我随意选择了我的视图的起始大小,因此缩放限制为2.0将等于全屏.我的较低比例设定为0.1.

用户交互:我搞砸了许多用户交互的事情,比如更改视图的背景颜色以及在视图上添加/更改箭头以显示方向.在缩放过程中给予他们反馈非常重要,尤其是在更改此代码允许的方向时.

BUG:Apple的UIPinchGestureRecognizer存在一个错误.它可以像你期望的那样用两根手指触摸UIGestureRecognizerStateBegan.但是一旦它在StateBegan或StateChanged,你可以抬起一根手指,状态仍然存在.在手指抬起之前,它不会移动到StateEnded或StateCancelled.这在我的代码中造成了一个错误,并且令人头疼!if numberOfTouches> 1修复了它.

未来:您可以将坡度设置更改为仅在一个方向上缩放,或者只是2.如果添加箭头图像,您可以在旋转手指时看到它们发生变化.