2012-08-23 55 views
1

我試圖創建一個類似於NSScrollView但基於CoreAnimation CAScrollLayer/CATiledLayer的自定義視圖。基本上,我的應用程序需要大量近實時的CGPath繪圖,並使用形狀圖層爲這些路徑加上動畫(它與GarageBand在錄製時動畫的方式類似)。我創建的第一個原型使用了NSScrollView,但是我無法獲得每秒20幀以上的數據(原因是NSRulerView每次發生scrollEvent都會進行更新,並且整個調用流從 - [NSClipView scrollToPoint]到[ NSScrollView reflectScrolledClipView:]是非常昂貴和低效的)。如何在OSX上實現scrollWheel彈性滾動

我創建了一個使用CAScrollLayer作爲滾動機制和CATiledLayer作爲傳統documentView(用於無限滾動選項)的自定義視圖,現在我可以接近60fps。但是,我很難實現scrollWheel彈性滾動,我不知道如何去做。這是我迄今爲止的代碼,如果有人能告訴我如何實現彈性滾動,我將非常感激。

-(void) scrollWheel:(NSEvent *)theEvent{ 
    NSCAssert(mDocumentScrollLayer, @"The Scroll Layer Cannot be nil"); 
    NSCAssert(mDocumentLayer, @"The tiled layer cannot be nil"); 
    NSCAssert(self.layer, @"The base layer of view cannot be nil"); 
    NSCAssert(mRulerLayer, @"The ScrollLayer for ruler cannot be nil"); 

    NSPoint locationInWindow = [theEvent locationInWindow]; 
    NSPoint locationInBaseLayer = [self convertPoint:locationInWindow 
             fromView:nil]; 


    NSPoint locationInRuler = [mRulerLayer convertPoint:locationInBaseLayer 
              fromLayer:self.layer]; 
    if ([mRulerLayer containsPoint:locationInRuler]) { 
     return; 
    } 
    CGRect docRect = [mDocumentScrollLayer convertRect:[mDocumentLayer bounds] 
              fromLayer:mDocumentLayer]; 

    CGRect scrollRect = [mDocumentScrollLayer visibleRect]; 
    CGPoint newOrigin = scrollRect.origin; 

    CGFloat deltaX = [theEvent scrollingDeltaX]; 
    CGFloat deltaY = [theEvent scrollingDeltaY]; 

    if ([self isFlipped]) { 
    deltaY *= -1; 
    } 

    scrollRect.origin.x -= deltaX; 
    scrollRect.origin.y += deltaY; 

    if ((NSMinX(scrollRect) < NSMinX(docRect)) || 
     (NSMaxX(scrollRect) > NSMaxX(docRect)) || 
     (NSMinY(scrollRect) < NSMinY(docRect)) || 
     (NSMaxY(scrollRect) > NSMaxX(docRect))) { 
     mIsScrollingPastEdge = YES; 
     CGFloat heightPhase = 0.0; 
     CGFloat widthPhase = 0.0; 
     CGSize size = [self frame].size; 

    if (NSMinX(scrollRect) < NSMinX(docRect)) { 
     widthPhase = ABS(NSMinX(scrollRect) - NSMinX(docRect)); 
    } 

    if (NSMaxX(scrollRect) > NSMaxX(docRect)) { 
     widthPhase = ABS(NSMaxX(scrollRect) - NSMaxX(docRect)); 
    } 

    if (NSMinY(scrollRect) < NSMinY(docRect)) { 
     heightPhase = ABS(NSMinY(scrollRect) - NSMinY(docRect)); 
    } 

    if (NSMaxY(scrollRect) > NSMaxY(docRect)) { 
     heightPhase = ABS(NSMaxY(scrollRect) - NSMaxY(docRect)); 
    } 

    if (widthPhase > size.width/2.0) { 
     widthPhase = size.width/2.0; 
    } 

    if (heightPhase > size.width/2.0) { 
     heightPhase = size.width/2.0; 
    } 

    deltaX = deltaX*(1-(2*widthPhase/size.width)); 
    deltaY = deltaY*(1-(2*heightPhase/size.height)); 
} 

newOrigin.x -= deltaX; 
newOrigin.y += deltaY; 

if (mIsScrollingPastEdge && 
    (([theEvent phase] == NSEventPhaseEnded) || 
    ([theEvent momentumPhase] == NSEventPhaseEnded) 
    ) 
    ){ 
    CGPoint confinedScrollPoint = [mDocumentScrollLayer bounds].origin; 
    mIsScrollingPastEdge = NO; 
    CGRect visibleRect = [mDocumentScrollLayer visibleRect]; 

    if (NSMinX(scrollRect) < NSMinX(docRect)){ 
     confinedScrollPoint.x = docRect.origin.x; 
    } 

    if(NSMinY(scrollRect) < NSMinY(docRect)) { 
     confinedScrollPoint.y = docRect.origin.y; 
    } 

    if (NSMaxX(scrollRect) > NSMaxX(docRect)) { 
     confinedScrollPoint.x = NSMaxX(docRect) - visibleRect.size.width; 
    } 

    if (NSMaxY(scrollRect) > NSMaxY(docRect)){ 
     confinedScrollPoint.y = NSMaxY(docRect) - visibleRect.size.height; 
    } 

    [mDocumentScrollLayer scrollToPoint:confinedScrollPoint]; 
    CGPoint rulerPoint = [mRulerLayer bounds].origin; 
    rulerPoint.x = [mDocumentLayer bounds].origin.x; 
    [mRulerLayer scrollToPoint:rulerPoint]; 
    return; 
} 

CGPoint rulerPoint = [mDocumentScrollLayer convertPoint:newOrigin 
               toLayer:mRulerLayer]; 
rulerPoint.y = [mRulerLayer bounds].origin.y; 

if (!mIsScrollingPastEdge) { 
    [CATransaction setDisableActions:YES]; 
    [mDocumentScrollLayer scrollToPoint:newOrigin]; 
    [CATransaction commit]; 
}else{ 
    [mDocumentScrollLayer scrollToPoint:newOrigin]; 
    [mRulerLayer scrollToPoint:rulerPoint]; 
} 

} 

回答