UIPinchGestureRecognizer ведет себя забавно, когда изображение увеличивается слишком большим - PullRequest
2 голосов
/ 02 ноября 2011

У меня есть простое приложение, в котором я присоединяю UIPinchGestureRecognizer и UIPanGestureRecognizer к imageView, чтобы я мог перетаскивать и масштабировать его. Я сделал это так, чтобы imageView можно было частично убрать с экрана и свернуть с дисплея, но небольшая 75-пиксельная часть изображения остается на дисплее, поэтому изображение можно перетаскивать обратно на него. Так, например, если я попытаюсь перетащить imageView из правой части экрана, он остановится, когда останется 75 пикселей imageView, оставляя достаточно места для меня, чтобы перетащить его обратно. То же самое относится и к масштабированию, создаваемый мной граничный кадр предотвращает сворачивание изображения с экрана.

Во всяком случае, у меня возникла эта проблема с моим кодом границы в методе делегата UIPinchGestureRecognizer. То, как я делаю границы, я создаю кадр, который является копией суперпредставления imageViews, за исключением того, что он выдвигается в 75 пикселей с каждой стороны, сверху и снизу. Я проверяю, не пересекается ли imageView с этим кадром, и затем я знаю, что он достиг одной из границ справа / слева или сверху / снизу. Это работает по большей части, однако, когда я увеличиваю изображение до довольно большого размера (обычно где-то более 1000 на 1000), граница не работает - если я делаю сверхбыстрый масштаб, изображение полностью исчезает с экрана. поэтому я не могу перетащить его обратно.

Мне просто интересно, почему это происходит. Связано ли это с тем, что размер изображения становится слишком большим? Или это недостаток в моем коде? (Я перечислил ниже). Если кто-то может помочь, будет признателен.

- (void)scale:(UIPinchGestureRecognizer *)sender 
{
    if([sender state] == UIGestureRecognizerStateBegan) 
    {
        lastScale = [sender scale];
    }

    if ([sender state] == UIGestureRecognizerStateBegan || 
        [sender state] == UIGestureRecognizerStateChanged) 
    {
        CGFloat currentScale = [[[sender view].layer valueForKeyPath:@"transform.scale"] floatValue];
        CGFloat newScale = 1 -  (lastScale - [sender scale]);// * (CropThePhotoViewControllerPinchSpeed);    
        newScale = MAX(newScale, CropThePhotoViewControllerMinScale / currentScale);

        CGFloat scaledWidth = newScale * sender.view.frame.size.width;
        CGFloat scaledHeight = newScale * sender.view.frame.size.height;

        CGRect translatedRect = CGRectMake(sender.view.frame.origin.x, sender.view.frame.origin.y, scaledWidth, scaledHeight);
        CGRect boundaryRect = CGRectMake(sender.view.superview.frame.origin.x + CropThePhotoViewControllerBoundaryBuffer, sender.view.superview.frame.origin.y + CropThePhotoViewControllerBoundaryBuffer, sender.view.superview.frame.size.width - (CropThePhotoViewControllerBoundaryBuffer * 2), sender.view.superview.frame.size.height - (CropThePhotoViewControllerBoundaryBuffer * 2));

        if (!(!CGRectIntersectsRect(boundaryRect,translatedRect) && newScale < 1))
        {
            CGAffineTransform transform = CGAffineTransformScale([[sender view] transform], newScale, newScale);
            [[sender view] setTransform: transform];
            lastScale = [sender scale];;
        }
    } 
}

Ответы [ 2 ]

2 голосов
/ 02 ноября 2011

Я заметил, что я должен проверить NaN (не число) результаты масштабирования, а затем разобраться с ними отдельно. Используйте isnan () для проверки.

1 голос
/ 03 ноября 2011

Я узнал, что случилось. Для этой строки кода я неправильно установил значения x и y:

CGRect translatedRect = CGRectMake(sender.view.frame.origin.x, sender.view.frame.origin.y, scaledWidth, scaledHeight);

Должно быть:

CGRect translatedRect = CGRectMake(sender.view.frame.origin.x + (((sender.view.frame.size.width - scaledWidth) / 2)), sender.view.frame.origin.y + (((sender.view.frame.size.height - scaledHeight) / 2)), scaledWidth, scaledHeight);

Я не учел тот факт, что источник должен был сдвинуться, когда изображение уменьшилось.

Я внес это изменение и фактически обновил метод для улучшения. Теперь вместо того, чтобы просто не выполнять масштабирование, если пользователь пытается минимизировать за пределы границы, вместо этого я перемещаю imageView прямо к границе. Это более гладко и в конечном итоге лучше имо. Он работает довольно хорошо после тестирования, но если кто-нибудь увидит какие-либо ошибки, пожалуйста, дайте мне знать:

- (void)scale:(UIPinchGestureRecognizer *)sender 
{
    if([sender state] == UIGestureRecognizerStateBegan) 
    {
        previousScale = [sender scale];
    }


    if ([sender state] == UIGestureRecognizerStateBegan || 
        [sender state] == UIGestureRecognizerStateChanged) 
    {
        CGFloat nextScale = 1 -  (previousScale - [sender scale]);// * (CropThePhotoViewControllerPinchSpeed); 

        nextScale = MAX(nextScale, CropThePhotoViewControllerMinScale / [[[sender view].layer valueForKeyPath:@"transform.scale"] floatValue]);

        CGFloat scaledWidth = nextScale * sender.view.frame.size.width;
        CGFloat scaledHeight = nextScale * sender.view.frame.size.height;
        CGFloat currentScale = [sender scale];

        CGRect translatedRect = CGRectMake(sender.view.frame.origin.x + (((sender.view.frame.size.width - scaledWidth) / 2)), sender.view.frame.origin.y + (((sender.view.frame.size.height - scaledHeight) / 2)), scaledWidth, scaledHeight);
        CGRect boundaryRect = CGRectMake(sender.view.superview.frame.origin.x + CropThePhotoViewControllerBoundaryBuffer, sender.view.superview.frame.origin.y + CropThePhotoViewControllerBoundaryBuffer, sender.view.superview.frame.size.width - (CropThePhotoViewControllerBoundaryBuffer * 2), sender.view.superview.frame.size.height - (CropThePhotoViewControllerBoundaryBuffer * 2));

        if ((!CGRectIntersectsRect(boundaryRect,translatedRect)) && (nextScale < 1))        
        {
            CGFloat leftScaledEdge, rightScaledEdge, topScaledEdge, bottomScaledEdge;
            CGFloat leftBoundary, rightBoundary, topBoundary, bottomBoundary;
            CGFloat nextXScale, nextYScale;

            nextXScale = CGFLOAT_MIN;
            nextYScale = CGFLOAT_MIN;

            rightScaledEdge = translatedRect.origin.x + translatedRect.size.width;
            leftScaledEdge = translatedRect.origin.x;
            bottomScaledEdge = translatedRect.origin.y + translatedRect.size.height;
            topScaledEdge = translatedRect.origin.y;

            leftBoundary = boundaryRect.origin.x;
            rightBoundary = boundaryRect.origin.x + boundaryRect.size.width; 
            topBoundary = boundaryRect.origin.y;
            bottomBoundary = boundaryRect.origin.y + boundaryRect.size.height;  

            if (rightScaledEdge < leftBoundary || leftScaledEdge > rightBoundary)
            {
                if (rightScaledEdge < leftBoundary)
                {
                    CGFloat adjustedWidth = sender.view.frame.size.width - fabsf((leftBoundary - (sender.view.frame.origin.x + sender.view.frame.size.width)));
                    nextXScale = (nextScale * (adjustedWidth)) / scaledWidth;
                }
                else
                {
                    CGFloat adjustedWidth = sender.view.frame.size.width - fabsf((rightBoundary - sender.view.frame.origin.x));
                    nextXScale = (nextScale * (adjustedWidth)) / scaledWidth;
                }
            }

            if (bottomScaledEdge < topBoundary || topScaledEdge > bottomBoundary)
            {
                if (bottomScaledEdge < topBoundary)
                {
                    CGFloat adjustedHeight = sender.view.frame.size.height - fabsf((topBoundary - (sender.view.frame.origin.y + sender.view.frame.size.height)));
                    nextYScale = (nextScale * (adjustedHeight)) / scaledHeight;
                }
                else
                {
                    CGFloat adjustedHeight = sender.view.frame.size.height - fabsf((bottomBoundary - sender.view.frame.origin.y));
                    nextYScale = (nextScale * (adjustedHeight)) / scaledHeight;

                }
            }

            if (nextXScale >= nextYScale)
            {
                nextScale = nextXScale;
            }
            else 
            {
                nextScale = nextYScale;
            }

            currentScale = nextScale - 1 + previousScale;
        }

        CGAffineTransform transform = CGAffineTransformScale([[sender view] transform], nextScale, nextScale);
        [[sender view] setTransform: transform];
        previousScale = currentScale;
    } 
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...