Масштабировать немасштабированные виды в UIScrollView до границ - PullRequest
11 голосов
/ 15 мая 2019

Мне нужно увеличить красные представления внутри серого представления до заданных красных границ (в этом случае границы представления прокрутки в зависимости от заданного соотношения ширины / высоты) внутри представления прокрутки, сохраняя видимые размеры видимых видов неизменными.Они также должны всегда касаться зеленой границы.

Я пытаюсь добиться этого, используя масштабные преобразования для этих видов, чтобы при масштабировании вида с прокруткой я уменьшал масштаб этих видов, используя формулу 1 / zoomScale, и меняя их опорные точки, чтобы они оставались на зеленой границе.

Проблема в том, что я не понимаю, как рассчитать целевой прямоугольник для красных видов после всех этих манипуляций, чтобы я мог перейти к нему, используя соответствующие zoomScale.

Пожалуйста, смотритеполный демонстрационный проект здесь

РЕДАКТИРОВАТЬ

Серый вид может выходить за границы просмотра с прокруткой (см. последнее изображение), главное, чтобы он соответствовал зеленый прямоугольник, окруженный красными видами (вы можете думать о них как о негативных вставках для зеленой области) внутри границ вида прокрутки, поэтому мы должны вычислить, принимая во внимание начальный и конечный размер зеленого прямоугольника, для которого красные видыдолжно быть «закреплено».

Основные методы

- (void)adjustScrollPositionAndZoomToFrame:(CGRect)frame
{
    CGFloat viewWidth = frame.size.width;
    CGFloat viewHeight = frame.size.height;

    CGFloat scrollViewWidth = self.scrollView.frame.size.width;
    CGFloat scrollViewHeight = self.scrollView.frame.size.height;

    CGSize newSize = [self scaleSize:frame.size toHeight:scrollViewHeight];

    if (newSize.width > scrollViewWidth) {
        newSize = [self scaleSize:frame.size toWidth:scrollViewWidth];
    }

    CGFloat scaleFactor = newSize.height == scrollViewHeight
        ? scrollViewHeight / viewHeight
        : scrollViewWidth / viewWidth;

    [self scrollRect:frame toCenterInScrollView:self.scrollView animated:NO];

    self.scrollView.zoomScale = scaleFactor;
}

Масштабирование

- (void)handleZoom:(CGFloat)zoom
{
    NSArray *anchorPoints = @[[NSValue valueWithCGPoint:CGPointMake(1.0, 1.0)],
                              [NSValue valueWithCGPoint:CGPointMake(0.5, 1.0)],
                              [NSValue valueWithCGPoint:CGPointMake(0.0, 1.0)],

                              [NSValue valueWithCGPoint:CGPointMake(1.0, 0.5)],
                              [NSValue valueWithCGPoint:CGPointMake(0.5, 0.5)],
                              [NSValue valueWithCGPoint:CGPointMake(0.0, 0.5)],

                              [NSValue valueWithCGPoint:CGPointMake(1.0, 0.0)],
                              [NSValue valueWithCGPoint:CGPointMake(0.5, 0.0)],
                              [NSValue valueWithCGPoint:CGPointMake(0.0, 0.0)]
                              ];

    for (UILabel *label in _labels) {
        [self setViewAnchorPoint:label value:[anchorPoints[[_labels indexOfObject:label]] CGPointValue]];
        label.transform = CGAffineTransformScale(CGAffineTransformIdentity, 1 / zoom, 1 / zoom);
    }
}

/**
 * @see https://stackoverflow.com/a/9649399/3004003
 * @param value See view.layer.anchorPoint
 */
- (void)setViewAnchorPoint:(UIView *)view value:(CGPoint)value
{
    CGPoint newPoint = CGPointMake(view.bounds.size.width * value.x,
                                   view.bounds.size.height * value.y);
    CGPoint oldPoint = CGPointMake(view.bounds.size.width * view.layer.anchorPoint.x,
                                   view.bounds.size.height * view.layer.anchorPoint.y);

    newPoint = CGPointApplyAffineTransform(newPoint, view.transform);
    oldPoint = CGPointApplyAffineTransform(oldPoint, view.transform);

    CGPoint position = view.layer.position;

    position.x -= oldPoint.x;
    position.x += newPoint.x;

    position.y -= oldPoint.y;
    position.y += newPoint.y;

    view.layer.position = position;
    view.layer.anchorPoint = value;
}

Начальная сцена перед увеличением:

enter image description here

Что у меня после увеличения:

enter image description here

Что мне нужно после увеличения:

enter image description here

Ответы [ 2 ]

1 голос
/ 25 мая 2019

Я скачал ваш проект и обнаружил следующие проблемы:

Когда вы инициализируете zoomingView, вы устанавливаете источник его фрейма так, чтобы zoomingView находился в середине scrollView.Когда вы затем масштабируете scrollView, он также масштабирует смещения к исходной точке, которые должны были быть приняты во внимание для правильного размещения масштабированного zoomingView.

Я думаю, что будет понятнее, если вы установите начало 0:

self.zoomingView = [[ZoomingView alloc] initWithFrame:CGRectMake(0, 0, kZoomingViewWidth, kZoomingViewHeight)];

После масштабирования zoomingView вам пришлось отцентрировать его.Это может быть сделано, например, с помощью

self.scrollView.zoomScale = scaleFactor;
    CGRect svb = self.scrollView.bounds;
    CGRect zvf = self.zoomingView.frame;
    self.scrollView.bounds = CGRectMake((zvf.size.width - svb.size.width)/2.0, (zvf.size.height - svb.size.height)/2.0, svb.size.width, svb.size.height);

Тогда следующая функция становится очень простой:

- (void)scrollViewDidZoom:(UIScrollView *)scrollView
{
   [self.zoomingView handleZoom:scrollView.zoomScale];
}

С этими изменениями масштабированный zoomingView отцентрирован правильно.

Однако коэффициент масштабирования по-прежнему неверен, поскольку внутренний зеленый прямоугольник масштабируется для заполнения доступного пространства.Причина в том, что нужно учитывать, что 2 поля размером 30 должны быть видны дополнительно, то есть доступное пространство для масштабирования меньше.Это может быть сделано, например,

CGFloat scaleFactor = newSize.height == scrollViewHeight
    ? (scrollViewHeight - 60.0) / viewHeight
    : (scrollViewWidth - 60.0) / viewWidth;

Конечно, константы должны были быть позже заменены на переменные.

С этими изменениями ваш код работает для меня правильно.

Еще одна вещь: В этом отличном посте подробно рассматриваются представления прокрутки.

0 голосов
/ 19 мая 2019

Что если изменить anchorPoints на значения:

NSArray *anchorPoints = @[[NSValue valueWithCGPoint:CGPointMake(0.0, 0.0)],
                          [NSValue valueWithCGPoint:CGPointMake(0.5, 0.0)],
                          [NSValue valueWithCGPoint:CGPointMake(1.0, 0.0)],

                          [NSValue valueWithCGPoint:CGPointMake(0.0, 0.5)],
                          [NSValue valueWithCGPoint:CGPointMake(0.5, 0.5)],
                          [NSValue valueWithCGPoint:CGPointMake(1.0, 0.5)],

                          [NSValue valueWithCGPoint:CGPointMake(0.0, 1.0)],
                          [NSValue valueWithCGPoint:CGPointMake(0.5, 1.0)],
                          [NSValue valueWithCGPoint:CGPointMake(1.0, 1.0)]
                          ];

Таким образом, вы откорректируете свои виды по краям масштаба и получите то, что вы хотите:

Result

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...