2009-08-18 42 views
14

Tôi đã có một NSView (myView) bọc trong một NSScrollView (myScrollView). Sử dụng các nút phóng to/thu nhỏ, người dùng có thể thay đổi tỷ lệ của myView. Nếu người dùng hiện đang được cuộn đến một vị trí cụ thể trong myView, tôi muốn giữ phần đó của chế độ xem trên màn hình sau khi quá trình thu phóng đã diễn ra.Làm thế nào để duy trì vị trí cuộn trong NSScrollView khi thay đổi tỷ lệ?

Tôi đã có mã mà trông như thế này:

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

Và có vẻ như loại gần, nhưng nó không hoàn toàn đúng và tôi không thể tìm ra những gì tôi đang làm sai. hai câu hỏi của tôi là:

1) Có không một built-in cái gì đó dọc theo dòng:

[myView adjustScaleBy: 0.5 whilePreservingLocationInScrollview:myScrollView]; 

2) Nếu không, ai cũng có thể thấy những gì tôi đang làm sai trong "chặng đường dài của tôi xung quanh "cách tiếp cận, ở trên?

Cảm ơn!

Trả lời

11

Giữ cùng một vị trí cuộn sau khi chia tỷ lệ không dễ dàng. Một điều bạn cần phải quyết định là những gì bạn có nghĩa là "giống nhau" - bạn có muốn phần trên cùng, giữa hoặc dưới của vùng hiển thị trước khi mở rộng quy mô để ở lại sau khi mở rộng quy mô không? Hoặc, trực quan hơn, bạn có muốn vị trí giữ nguyên tỷ lệ phần trăm có thể nhìn thấy bằng phần trăm mà bạn được cuộn xuống tài liệu khi bạn bắt đầu (ví dụ như vậy, trung tâm của ngón tay cái của chuột không ' t di chuyển lên hoặc xuống trong một quy mô, ngón tay cái chỉ phát triển hoặc co lại).

Nếu bạn muốn hiệu ứng thứ hai, một cách để thực hiện điều đó là lấy VerticalScroller và HorizontalScroller của NSScrollView, sau đó đọc 'floatValue's'. Chúng được chuẩn hóa từ 0 đến 1, trong đó '0' có nghĩa là bạn đang ở trên cùng của tài liệu và 1 có nghĩa là bạn đang ở cuối. Điều tốt đẹp về việc yêu cầu cuộn cho điều này là nếu tài liệu ngắn hơn NSScrollView, trình cuộn vẫn trả về một câu trả lời lành mạnh trong mọi trường hợp cho 'floatValue', vì vậy bạn không phải đặc biệt trong trường hợp này.

Sau khi bạn thay đổi kích thước, hãy đặt vị trí cuộn của NSScrollView thành tỷ lệ tương tự trước thang đo - nhưng, thật đáng buồn, đây là nơi tôi vẫy tay một chút. Tôi đã không làm điều này trong một thời gian trong mã của tôi, nhưng như tôi nhớ bạn không thể chỉ đặt trực tiếp NSScrollers 'floatValue - họ sẽ LOOK cuộn, nhưng họ sẽ không thực sự ảnh hưởng đến NSScrollView.

Vì vậy, bạn sẽ phải viết một số phép tính để tính điểm mới trên cùng bên trái trong tài liệu của mình dựa trên phần trăm bạn muốn trải qua - trên trục y, ví dụ, nó sẽ trông giống như, "Nếu tài liệu bây giờ ngắn hơn nội dung scrollView của scrollView, di chuyển đến điểm 0, nếu không di chuyển đến một điểm đó ((chiều cao của contentView - chiều cao của documentView) * oldVerticalPercentage) xuống tài liệu." X trục là tất nhiên tương tự.

Ngoài ra, tôi gần như tích cực, bạn không cần phải gọi đến -display tại đây và nói chung không bao giờ nên gọi nó, bao giờ hết. (-setNeedsDisplay:. Nhiều nhất)

-Wil

+0

Hiệu ứng tôi muốn là: giả sử tôi đang nhìn vào giữa màn hình. Khi tôi phóng to (hoặc -out), hãy giữ điều đó ở giữa màn hình. Cảm ơn! – Olie

+0

Câu trả lời tuyệt vời! Thay vì đặt floatValue trên các thanh cuộn sau khi tôi đã cuộn chế độ xem của tôi về nguồn gốc được tính toán, tôi gọi là reflectScrolledClipView: trên chế độ xem cuộn của tôi. Điều này dường như có được các thanh cuộn ở đúng vị trí. Không chắc chắn nếu điều này là chính xác vì đây là ứng dụng Mac đầu tiên tôi đã tạo ra, nhưng nó làm việc cho tôi. – afarnham

7

nhớ rằng bạn muốn gõ quá nhiều ... ;-)

// 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); 
+0

Vâng, tôi đã học được những điều đó ngay sau khi đăng. Tôi đến từ thế giới iPhone, và đoán tên NS cho mọi thứ vẫn còn hơi chậm đối với tôi. Cảm ơn! :) – Olie

6

Đây là một câu hỏi cũ, nhưng tôi hy vọng ai đó tìm kiếm này tìm thấy câu trả lời của tôi hữu ích ...

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]; 
} 
+0

Tôi thấy nó khá hữu ích. Điều này làm việc, sau khi tôi đã thử một số thứ khác mà không. Cảm ơn bạn đã đăng bài! – jbillfinger

+1

Công trình này tuyệt vời! Vấn đề duy nhất là khi thay đổi kích thước cửa sổ (và do đó chế độ xem cuộn): nội dung được cuộn xuống dưới cùng bên trái một lần nữa. –

+0

@NicolasMiari Tôi cũng gặp sự cố khi nội dung được cuộn xuống dưới cùng bên trái, bạn đã tìm thấy giải pháp chưa? –

Các vấn đề liên quan