NSScrollView: исчезают на верхней границе, например Messages.app

Что я хочу сделать:

В Messages.app в OS 10.10, когда вы прокручиваете крайнюю левую панель (список разговоров) вверх, красивая горизонтальная линия исчезает примерно через 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
        }
    }
}

Проблема

Подслой "граница", который я добавляю, не отрисовывается поверх всего остального содержимого в ScrollView, так что в итоге мы получаем следующее:

введите описание изображения здесь

Рамки вокруг изображения, текстового поля и флажка в этой строке моего OutlineView «перекрывают» мой пограничный слой.

Что вызывает это

Я ДУМАЮ, это потому, что scrollView содержится внутри NSVisualEffectView, в котором включена Vibrancy. Причина, по которой я думаю, заключается в том, что если я изменю цвет моего подслоя «границы» на 100% черный, эта проблема исчезнет. Аналогичным образом, если я включу «Уменьшить прозрачность» в Системных настройках OS X> Доступность, проблема исчезнет.

Я думаю, что композиция Vibrancy берет мой подслой с серой рамкой и слои, которые представляют каждый из этих компонентов в строке outlineView, и убирает цвета.

Итак ... как мне остановить это для одного слоя? Я пробовал все, что угодно, чтобы с этим справиться. Я чувствую, что на 99% прошел путь к надежной реализации, но не могу исправить эту последнюю проблему. Кто-нибудь может помочь?


NB:

Я знаю, что опасно гадить напрямую со слоями в среде с поддержкой слоев. В документации Apple четко указано, что мы не можем изменить определенные свойства слоя представления, если мы используем поддержку слоев. Однако: добавление и удаление подслоев (как и я) не является запрещенным действием.


person Bryan    schedule 29.05.2015    source источник


Ответы (1)


Обновлять:

Этот ответ, хотя и работает, вызывает проблемы, если вы используете AutoLayout. Вы начнете получать предупреждения о том, что scrollView все еще нуждается в обновлении после вызова Layout, потому что что-то загрязнило макет в середине обновления. Мне пока не удалось найти обходной путь.


Оригинальное решение:

Самый простой способ решить проблему - просто вставить contentView по высоте подуровня границы следующим образом:

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

Надо было подумать об этом несколько часов назад. Работает отлично. Я оставлю вопрос всем, кто может захотеть реализовать эти красивые fading-border.

person Bryan    schedule 29.05.2015