5

UI/NSTableView için yeniden kullanılabilir hücreler gibi bir şey uygulamak için bir yol arıyorum, ancak NSScrollView için. Temelde WWDC 2011 videosu "Oturum 104 - Gelişmiş Scroll View Teknikleri" gibi ama Mac için de istiyorum.NSScrollView sonsuz/sonsuz kaydırma | alt görünüm yeniden

Bunu fark etmemde bazı problemlerim var. İlk: NSScrollView, -layoutSubviews'a sahip değil. Ben farklı bir contentOffset ayar yerine -adjustScroll kullanmak ancak başarısız çalıştı: Denedim

- (NSRect)adjustScroll:(NSRect)proposedVisibleRect { 
    if (proposedVisibleRect.origin.x > 600) { 
     // non of them work properly 
     // proposedVisibleRect.origin.x = 0; 
     // [self setBoundsOrigin:NSZeroPoint]; 
     // [self setFrameOrigin:NSZeroPoint]; 
     // [[parentScrollView contentView] scrollPoint:NSZeroPoint]; 
     // [[parentScrollView contentView] setBoundsOrigin:NSZeroPoint]; 
    } 
    return proposedVisibleRect; 
} 

sonraki şey iOS kıyasla gerçekten çalışıyor pikselin milyonlarca (bir width ile gerçekten büyük içerik görünümünü ayarlamak için oldu!) ama şimdi soru, yeniden kullanım havuzu nasıl kurulur?
Altyazıları yeni bir konuma kaydırırken veya tüm alt görünümleri kaldırmak ve tekrar eklemek için mi daha iyi olur? ve bunu nasıl ve nerede yapmalıyım?

cevap

2

En iyi şekilde anladığım kadarıyla, -adjustScroll:, evrensel olarak çağrılmadığı için kaydırma olaylarına gitmek istediğiniz yer değil. Bence -reflectScrolledClipView: muhtemelen daha iyi bir bağlantı noktasıdır.

Görünümü yeniden görüntüleyerek kaydırma görünümünü yapmak için tek yönden yüksek noktalara çarpması gereken aşağıdaki örnekte pişirdim. Basitlik açısından, scrollView'ın belgesinin boyutlarını, önerdiğiniz gibi, kaydırma davranışını sonsuza kadar "uydurmaya" çalışmak yerine "devasa" olarak ayarladım. Açıkçası, kurucu karo görünümlerini gerçek yapmak size kalmış. (Bu örnekte Herşeyin çalıştığını kendimi ikna etmeye mavi anahat kırmızı kendisini doldurur bir kukla görünüm yarattı.) Böyle çıktı: Bu oldukça iyi anlarım gelebilecek en iyi olarak çalıştı

// For the header file 
@interface SOReuseScrollView : NSScrollView 
@end 

// For the implementation file 
@interface SOReuseScrollView() // Private 

- (void)p_updateTiles; 
@property (nonatomic, readonly, retain) NSMutableArray* p_reusableViews; 

@end 

// Just a small diagnosting view to convince myself that this works. 
@interface SODiagnosticView : NSView 
@end 

@implementation SOReuseScrollView 

@synthesize p_reusableViews = mReusableViews; 

- (void)dealloc 
{ 
    [mReusableViews release]; 
    [super dealloc]; 
} 

- (NSMutableArray*)p_reusableViews 
{ 
    if (nil == mReusableViews) 
    { 
     mReusableViews = [[NSMutableArray alloc] init]; 
    } 
    return mReusableViews; 
} 

- (void)reflectScrolledClipView:(NSClipView *)cView 
{ 
    [super reflectScrolledClipView: cView]; 
    [self p_updateTiles]; 
} 

- (void)p_updateTiles 
{ 
    // The size of a tile... 
    static const NSSize gGranuleSize = {250.0, 250.0}; 

    NSMutableArray* reusableViews = self.p_reusableViews; 
    NSRect documentVisibleRect = self.documentVisibleRect; 

    // Determine the needed tiles for coverage 
    const CGFloat xMin = floor(NSMinX(documentVisibleRect)/gGranuleSize.width) * gGranuleSize.width; 
    const CGFloat xMax = xMin + (ceil((NSMaxX(documentVisibleRect) - xMin)/gGranuleSize.width) * gGranuleSize.width); 
    const CGFloat yMin = floor(NSMinY(documentVisibleRect)/gGranuleSize.height) * gGranuleSize.height; 
    const CGFloat yMax = ceil((NSMaxY(documentVisibleRect) - yMin)/gGranuleSize.height) * gGranuleSize.height; 

    // Figure out the tile frames we would need to get full coverage 
    NSMutableSet* neededTileFrames = [NSMutableSet set]; 
    for (CGFloat x = xMin; x < xMax; x += gGranuleSize.width) 
    { 
     for (CGFloat y = yMin; y < yMax; y += gGranuleSize.height) 
     { 
      NSRect rect = NSMakeRect(x, y, gGranuleSize.width, gGranuleSize.height); 
      [neededTileFrames addObject: [NSValue valueWithRect: rect]]; 
     } 
    } 

    // See if we already have subviews that cover these needed frames. 
    for (NSView* subview in [[[self.documentView subviews] copy] autorelease]) 
    { 
     NSValue* frameRectVal = [NSValue valueWithRect: subview.frame]; 

     // If we don't need this one any more... 
     if (![neededTileFrames containsObject: frameRectVal]) 
     { 
      // Then recycle it... 
      [reusableViews addObject: subview]; 
      [subview removeFromSuperview]; 
     } 
     else 
     { 
      // Take this frame rect off the To-do list. 
      [neededTileFrames removeObject: frameRectVal]; 
     } 
    } 

    // Add needed tiles from the to-do list 
    for (NSValue* neededFrame in neededTileFrames) 
    { 
     NSView* view = [[[reusableViews lastObject] retain] autorelease]; 
     [reusableViews removeLastObject]; 

     if (nil == view) 
     { 
      // Create one if we didnt find a reusable one. 
      view = [[[SODiagnosticView alloc] initWithFrame: NSZeroRect] autorelease]; 
      NSLog(@"Created a view."); 
     } 
     else 
     { 
      NSLog(@"Reused a view."); 
     } 

     // Place it and install it. 
     view.frame = [neededFrame rectValue]; 
     [view setNeedsDisplay: YES];   
     [self.documentView addSubview: view]; 
    } 
} 

@end 

@implementation SODiagnosticView 

- (void)drawRect:(NSRect)dirtyRect 
{ 
    // Draw a red tile with a blue border. 
    [[NSColor blueColor] set]; 
    NSRectFill(self.bounds); 

    [[NSColor redColor] setFill]; 
    NSRectFill(NSInsetRect(self.bounds, 2,2));  
} 

@end 

. Yine, tekrarlanan görüşlerde anlamlı bir şey çizmek, gerçek işin burada olduğu yerdir.

Bu yardımcı olur umarım.

+0

Bir çekicilik gibi çalışır, teşekkür ederim. Sonraki günlerde otomatikleştirmeyi ve diğer özelleştirmeleri desteklemek için daha derine ineceğim =) –

İlgili konular