NSScrollView:像Messages.app

时间:2015-05-29 10:00:19

标签: objective-c cocoa core-animation calayer nsscrollview

我想做什么:

在OS 10.10上的Messages.app中,向上滚动最左侧窗格(对话列表)时,一条漂亮的水平线会在大约0.5秒内消失。当您向下滚动时,该线会淡出。

我有什么:

我正在尝试在我自己的应用程序中实现此效果,并且我已经非常接近了。我将NSScrollView子类化并执行了以下操作:

- (void) awakeFromNib
{
    _topBorderLayer = [[CALayer alloc] init];

    CGColorRef bgColor = CGColorCreateGenericGray(0.8, 1.0f);
    _topBorderLayer.backgroundColor = bgColor;
    CGColorRelease(bgColor);

    _topBorderLayer.frame = CGRectMake(0.0f, 0.0f, self.bounds.size.width, 1.0f);
    _topBorderLayer.autoresizingMask = kCALayerWidthSizable;
    _topBorderLayer.zPosition = 1000000000;

    _fadeInAnimation = [[CABasicAnimation animationWithKeyPath:@"opacity"] retain];
    _fadeInAnimation.duration = 0.6f;
    _fadeInAnimation.fromValue = @0;
    _fadeInAnimation.toValue = @1;
    _fadeInAnimation.removedOnCompletion = YES;
    _fadeInAnimation.fillMode = kCAFillModeBoth;

    [self.layer insertSublayer:_topBorderLayer atIndex:0];
}
- (void) layoutSublayersOfLayer:(CALayer *)layer
{
    NSPoint origin = [self.contentView documentVisibleRect].origin;

    // 10 is a fudge factor for blank space above first row's actual content
    if (origin.y > 10)
    {
        if (!_topBorderIsShowing)
        {
            _topBorderIsShowing = YES;
            [_topBorderLayer addAnimation:_fadeInAnimation forKey:nil];
            _topBorderLayer.opacity = 1.0f; 
        }
    }
    else
    {
        if (!_topBorderIsShowing)
        {
            _topBorderIsShowing = NO;
            // Fade out animation here; omitted for brevity
        }
    }
}

问题

我添加的“border”子图层并未覆盖ScrollView中所有其他内容的顶部,因此我们最终得到了这个:

enter image description here

我的outlineView的这一行中的图像,文本字段和复选框周围的框架正在“透支”我的边框图层。

原因是什么

我认为这是因为scrollView包含在启用了Vibrancy的NSVisualEffectView中。我认为这是因为如果我将“边框”子图层的颜色更改为100%黑色,则此问题会消失。同样,如果我在OS X的系统偏好设置中打开“减少透明度”>可访问性,问题消失了。

我认为Vibrancy合成正在使用我的灰色边框子图层以及代表outlineView行中每个组件的图层并将颜色弄清楚。

那么......我如何阻止单层?我已经尝试过各种各样的东西来克服这个问题。我觉得我有99%的方法可以实现可靠的实现,但无法解决最后一个问题。有人可以帮忙吗?

NB:

我知道在层支持的环境中直接粘贴图层是很危险的。 Apple的文档清楚地表明,如果我们使用图层支持,我们就无法更改视图图层的某些属性。但是:添加和删除子图层(就像我一样)不是禁止的操作。

1 个答案:

答案 0 :(得分:2)

更新

如果您使用AutoLayout,这个答案虽然有效但会导致问题。在调用Layout之后,您将开始收到有关scrollView仍需要更新的警告,因为在更新过程中某些内容会使布局变脏。我还没有找到解决办法。

原始解决方案:

解决问题的最简单方法就是用边框子图层的高度插入contentView:

- (void) tile
{
    id contentView = [self contentView];
    [super tile];
    [contentView setFrame:NSInsetRect([contentView frame], 0.0, 1.0)];
}

几小时前应该想到它。效果很好。对于那些可能正在寻求实现这些漂亮的褪色边框的人,我会留下这个问题。