Как сохранить положение прокрутки в NSScrollView при изменении масштаба?

StackOverflow https://stackoverflow.com/questions/1296920

Вопрос

У меня есть NSView (MyView), завернутый в NSScrollView (myScrollView).Используя кнопки увеличения / уменьшения масштаба, пользователь может изменять масштаб MyView.Если пользователь в данный момент прокручивается до определенного места в MyView, я бы хотел сохранить эту часть представления на экране после того, как произойдет масштабирование.

У меня есть код, который выглядит примерно так:

    // preserve current position in scrollview
    NSRect oldVisibleRect = [[myScrollView contentView] documentVisibleRect];
    NSPoint oldCenter = NSPointFromCGPoint(CGPointMake(oldVisibleRect.origin.x + (oldVisibleRect.size.width  / 2.0),
                                                       oldVisibleRect.origin.y + (oldVisibleRect.size.height / 2.0)));

    // adjust my zoom
    ++displayZoom;
    [self scaleUnitSquareToSize:NSSizeFromCGSize(CGSizeMake(0.5, 0.5))];
    [self calculateBounds];  // make sure my frame & bounds are at least as big as the visible content view
    [self display];

    // Adjust scroll view to keep the same position.
    NSRect newVisibleRect = [[myScrollView contentView] documentVisibleRect];
    NSPoint newOffset = NSPointFromCGPoint(CGPointMake((oldCenter.x * 0.5) - (newVisibleRect.size.width  / 2.0),
                                                       (oldCenter.y * 0.5) - (newVisibleRect.size.height / 2.0)));
    if (newOffset.x < 0)
        newOffset.x = 0;
    if (newOffset.y < 0)
        newOffset.y = 0;

    [[myScrollView contentView] scrollToPoint: newOffset];
    [myScrollView reflectScrolledClipView: [myScrollView contentView]];

И это кажется вроде как близким, но это не совсем правильно, и я не могу понять, что я делаю не так.Мои два вопроса заключаются в следующем:

1) Нет ли встроенного чего-то вроде:

   [myView adjustScaleBy: 0.5 whilePreservingLocationInScrollview:myScrollView];

2) Если нет, может ли кто-нибудь увидеть, что я делаю неправильно в моем подходе "долгий путь", описанном выше?

Спасибо!

Это было полезно?

Решение

Сохранить то же положение прокрутки после масштабирования непросто.Одна вещь, которую вам нужно решить, это то, что вы подразумеваете под "тем же самым" - хотите ли вы, чтобы верхняя, средняя или нижняя часть видимой области до масштабирования оставалась на месте после масштабирования?

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

Если вы хотите получить последний эффект, один из способов сделать это - получить verticalScroller и horizontalScroller от NSScrollView, а затем прочитать их 'floatValue' .Они нормализованы от 0 до 1, где '0' означает, что вы находитесь в верхней части документа, а 1 означает, что вы находитесь в конце.Хорошая вещь в запросе скроллера об этом заключается в том, что если документ короче, чем NSScrollView, скроллер все равно возвращает нормальный ответ во всех случаях для 'floatValue', так что вам не нужно использовать специальный случай для этого.

После изменения размера установите положение прокрутки NSScrollView на тот же процент, что и до изменения масштаба, но, к сожалению, здесь я немного машу руками.Я давно не делал этого в своем коде, но, насколько я помню, вы не можете просто напрямую установить значения floatValue для NSScrollers - они будут выглядеть прокрученными, но на самом деле не повлияют на NSScrollView.

Итак, вам придется написать некоторую математику, чтобы вычислить новую верхнюю левую точку в вашем документе на основе процента, который вы хотите пройти через нее - например, по оси y это будет выглядеть так: "Если документ теперь короче, чем contentView в ScrollView, прокрутите до точки 0, в противном случае прокрутите до точки, которая ((высота contentView - высота documentView) * oldVerticalPercentage) находится в нижней части документа". Ось X, конечно, аналогична.

Кроме того, я почти уверен, что вам не нужен вызов -display здесь, и вообще никогда не следует его вызывать, никогда.(-Установить необходимость отображения:самое большее.)

-Уил

Другие советы

Мне кажется, тебе слишком много нравится печатать ... ;-)

// instead of this:
NSPoint oldCenter = NSPointFromCGPoint(CGPointMake(oldVisibleRect.origin.x +
    (oldVisibleRect.size.width  / 2.0),

// use this:
NSPoint oldCenter = NSMakePoint(NSMidX(oldVisibleRect), NSMaxY(oldVisibleRect));

// likewise instead of this:
[self scaleUnitSquareToSize:NSSizeFromCGSize(CGSizeMake(0.5, 0.5))];

// use this:
[self scaleUnitSquareToSize:NSMakeSize(0.5, 0.5)];

// and instead of this
NSPoint newOffset = NSPointFromCGPoint(CGPointMake(
    (oldCenter.x * 0.5) - (newVisibleRect.size.width  / 2.0),
    (oldCenter.y * 0.5) - (newVisibleRect.size.height / 2.0)));

// use this:
NSPoint newOffset NSMakePoint(
    (oldCenter.x - NSWidth(newVisibleRect)) / 2.f,
    (oldCenter.y - NSHeight(newVisibleRect)) / 2.f);

Это старый вопрос, но я надеюсь, что кто-то, ищущий этот вопрос, найдет мой ответ полезным...

float zoomFactor = 1.3;

-(void)zoomIn
{
    NSRect visible = [scrollView documentVisibleRect];
    NSRect newrect = NSInsetRect(visible, NSWidth(visible)*(1 - 1/zoomFactor)/2.0, NSHeight(visible)*(1 - 1/zoomFactor)/2.0);
    NSRect frame = [scrollView.documentView frame];

    [scrollView.documentView scaleUnitSquareToSize:NSMakeSize(zoomFactor, zoomFactor)];
    [scrollView.documentView setFrame:NSMakeRect(0, 0, frame.size.width * zoomFactor, frame.size.height * zoomFactor)];

    [[scrollView documentView] scrollPoint:newrect.origin];
}

-(void)zoomOut
{
    NSRect visible = [scrollView documentVisibleRect];
    NSRect newrect = NSOffsetRect(visible, -NSWidth(visible)*(zoomFactor - 1)/2.0, -NSHeight(visible)*(zoomFactor - 1)/2.0);

    NSRect frame = [scrollView.documentView frame];

    [scrollView.documentView scaleUnitSquareToSize:NSMakeSize(1/zoomFactor, 1/zoomFactor)];
    [scrollView.documentView setFrame:NSMakeRect(0, 0, frame.size.width / zoomFactor, frame.size.height / zoomFactor)];

    [[scrollView documentView] scrollPoint:newrect.origin];
}
Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top