كيفية الحفاظ على وضع التمرير في 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 NSSCrollView's VerticalScroller و Horizontalscroller، ثم قراءة "Floatvalue". يتم تطبيع هذه من 0 إلى 1، حيث تعني "0" أنك في الجزء العلوي من المستند و 1 تعني أنك في النهاية. الشيء اللطيف حول طرح التمرير لهذا هو أنه إذا كانت المستند أقصر من NSSCrollView، فإن Scroller لا يزال بإرجاع إجابة عاقلة في جميع الحالات ل "Floatvalue"، حتى لا تضطر إلى هذا القضية الخاصة.

بعد تغيير الحجم، قم بتعيين موضع التمرير NSSCrollView لتكون النسبة المئوية هي نفسها قبل النطاق - ولكن للأسف، إليك هنا أطومني بيدي قليلا. لم أفعل ذلك منذ فترة أثناء وجودك في التعليمات البرمجية، ولكن كما أتذكر أنك لا تستطيع فقط تعيين NSSCrollers "Floatvalue" مباشرة - سوف تبدو تمريرة، لكنها لن تؤثر فعليا على NSSCrollView.

لذلك، عليك أن تكتب بعض الرياضيات لحساب النقطة الجديدة العلوية الجديدة في وثيقتك بناء على النسبة المئوية التي تريد أن تكون من خلالها - على المحور Y، على سبيل المثال، سوف تبدو وكأنها "إذا كانت المستند أقصر الآن من ScrollView's ContentView، قم بالتمرير إلى النقطة 0، وإلا يتم تمريرها إلى حد ما ((ارتفاع ContentView - ارتفاع المستندات) * OldvertItyPernerate) لأسفل المستند. " X محور هو بالطبع مماثلة.

أيضا، أنا إيجابي تقريبا، لا تحتاج إلى دعوة إلى -display هنا، وعليه لا ينبغي أن يطلق عليه أي وقت مضى، على الإطلاق. (-SetneedsdisPlay: على الأكثر.)

-wil.

نصائح أخرى

أنا أعتقد أنك ترغب في كتابة الكثير ...-)

// 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