gpt4 book ai didi

objective-c - NSScrollView 无限/无限滚动 | subview 重用

转载 作者:太空狗 更新时间:2023-10-30 03:54:16 30 4
gpt4 key购买 nike

我正在寻找一种方法来为 UI/NSTableView 但为 NSScrollView 实现可重用单元格之类的东西。基本上我想要与 WWDC 2011 视频“Session 104 - Advanced Scroll View Techniques”相同但适用于 Mac。

我在实现这一点时遇到了几个问题。第一个:NSScrollView 没有 -layoutSubviews。我尝试改用 -adjustScroll 但未能设置不同的 contentOffset:

- (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;
}

我尝试的下一件事是设置一个非常大的内容 View ,宽度 为数百万像素(与 iOS 相比,这确实有效!)但现在的问题是,如何安装一个重用池?
在滚动到新位置时移动 subview 或删除所有 subview 并再次插入它们更好吗?我应该如何以及在哪里做?

最佳答案

据我所知,-adjustScroll: 不是您想要利用滚动事件的地方,因为它不会被普遍调用。我认为 -reflectScrolledClipView: 可能是一个更好的连接点。

我编写了以下示例,该示例应该达到了执行 View 重用 ScrollView 的一种方式的要点。为简单起见,我将 scrollView 的 documentView 的尺寸设置为“巨大”,正如您所建议的,而不是试图“伪造”滚动行为以使其看起来无限。显然,真正绘制构成图 block View 取决于您。 (在这个例子中,我创建了一个虚拟 View ,它只用红色和蓝色轮廓填充自己,以说服自己一切正常。)结果是这样的:

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

据我所知,这非常有效。同样,在重用的 View 中绘制一些有意义的东西才是真正的工作所在。

希望对您有所帮助。

关于objective-c - NSScrollView 无限/无限滚动 | subview 重用,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/9115944/

30 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com