NSScrollView:像 Messages.app 这样的顶部边框淡入淡出
NSScrollView: fade in a top-border like Messages.app
我想做什么:
在 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 中所有其他内容之上,所以我们最终得到这个:
我的 outlineView 这一行中图像、文本字段和复选框周围的框架是 "overdrawing" 我的边框层。
这是什么原因造成的
我认为这是因为 scrollView 包含在启用了 Vibrancy 的 NSVisualEffectView 中。我认为这是因为如果我将 "border" 子层的颜色更改为 100% 黑色,这个问题就会消失。同样,如果我在 OS X 的系统偏好设置 > 辅助功能中打开 "Reduce Transparency",问题就会消失。
我认为 Vibrancy 合成正在使用我的灰色边框子图层和代表 outlineView 行中每个组件的图层并混淆颜色。
所以...我如何停止单层?我已经尝试了各种方法来克服这个问题。我觉得我已经完成了 99% 的可靠实施,但无法解决最后一个问题。有人可以帮忙吗?
注意:
我知道在支持层的环境中直接处理层是危险的。 Apple 的文档清楚地表明,如果我们使用图层支持,我们将无法更改视图图层的某些属性。然而:添加和删除子层(就像我一样)不是被禁止的行为。
更新:
这个答案虽然有效,但如果您使用的是 AutoLayout,就会出现问题。在调用 Layout 之后,您将开始收到 scrollView 仍然需要更新的警告,因为在更新过程中某些东西弄脏了布局。我还没有找到解决方法。
原解:
解决这个问题的最简单方法就是将 contentView 插入边框子层的高度:
- (void) tile
{
id contentView = [self contentView];
[super tile];
[contentView setFrame:NSInsetRect([contentView frame], 0.0, 1.0)];
}
几个小时前就应该想到了。效果很好。我会将问题留给可能希望实现这些漂亮的淡化边界的任何人。
我想做什么:
在 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 中所有其他内容之上,所以我们最终得到这个:
我的 outlineView 这一行中图像、文本字段和复选框周围的框架是 "overdrawing" 我的边框层。
这是什么原因造成的
我认为这是因为 scrollView 包含在启用了 Vibrancy 的 NSVisualEffectView 中。我认为这是因为如果我将 "border" 子层的颜色更改为 100% 黑色,这个问题就会消失。同样,如果我在 OS X 的系统偏好设置 > 辅助功能中打开 "Reduce Transparency",问题就会消失。
我认为 Vibrancy 合成正在使用我的灰色边框子图层和代表 outlineView 行中每个组件的图层并混淆颜色。
所以...我如何停止单层?我已经尝试了各种方法来克服这个问题。我觉得我已经完成了 99% 的可靠实施,但无法解决最后一个问题。有人可以帮忙吗?
注意:
我知道在支持层的环境中直接处理层是危险的。 Apple 的文档清楚地表明,如果我们使用图层支持,我们将无法更改视图图层的某些属性。然而:添加和删除子层(就像我一样)不是被禁止的行为。
更新:
这个答案虽然有效,但如果您使用的是 AutoLayout,就会出现问题。在调用 Layout 之后,您将开始收到 scrollView 仍然需要更新的警告,因为在更新过程中某些东西弄脏了布局。我还没有找到解决方法。
原解:
解决这个问题的最简单方法就是将 contentView 插入边框子层的高度:
- (void) tile { id contentView = [self contentView]; [super tile]; [contentView setFrame:NSInsetRect([contentView frame], 0.0, 1.0)]; }
几个小时前就应该想到了。效果很好。我会将问题留给可能希望实现这些漂亮的淡化边界的任何人。