2015-03-17 3 views
15

Я пытаюсь создать пользовательский NSView, на котором размещена иерархия CALayer для эффективного отображения. Этот NSView затем встроен в NSTableCellView, который отображается на основе NSOutlineView.Layer hosting NSView в NSOutlineView

Проблема заключается в том, что всякий раз, когда я расширяю или сворачиваю элемент, все строки перемещаются, но содержимое слоя остается отображаемым в позиции, которая была до изменения контура.

Прокрутка NSOutlineView, похоже, обновляет слои, и они повторно синхронизируют свои строки в этой точке.

Я отлаживал это поведение с помощью инструментов, и кажется, что прокрутка провоцирует операцию макета, которая обновляет слои вызовом setPosition:, который должен был произойти при расширении или свертывании элементов.

Вот пример кода для простого уровня хостинга NSView подкласса.

@interface TestView : NSView 

@end 

@implementation TestView 

- (instancetype)initWithFrame:(NSRect)frameRect 
{ 
    self = [super initWithFrame:frameRect]; 
    CAShapeLayer* layer = [CAShapeLayer layer]; 
    layer.bounds = self.bounds; 
    layer.position = CGPointMake(NSMidX(self.bounds), NSMidY(self.bounds)); 
    layer.path = [NSBezierPath bezierPathWithOvalInRect:self.bounds].CGPath; 
    layer.fillColor = [NSColor redColor].CGColor; 
    layer.delegate = self; 
    self.layer = layer; 
    self.wantsLayer = YES; 
    return self; 
} 

@end 

Я пробовал много возможных решений этой проблемы, но я не мог найти какой-либо интересный метод, который вызывается на NSView экземпляра, который может быть переопределен для вызова [self.layer setNeedsDisplay] или [self.layer setNeedsLayout]. Я также пробовал различные сеттер на самом CALayer, такие как:

layer.autoresizingMask = kCALayerWidthSizable | kCALayerHeightSizable; 
layer.needsDisplayOnBoundsChange = YES; 
self.layerContentsRedrawPolicy = NSViewLayerContentsRedrawOnSetNeedsDisplay; 

Может кто-нибудь помочь мне понять, как сделать этот дисплей слоя правильно внутри NSOutlineView?

ответ

5

В итоге я ответил на свой вопрос. Проблема была не в том, как мой TestView был реализован. Я просто пропустил один из шагов для поддержки поддержки CoreAnimation в приложении. Соответствующая ссылка находится в руководстве по программированию основной анимации.

В принципе, в iOS Core Анимация и поддержка слоев всегда включены по умолчанию. На OS X, он должен быть включен таким образом:

  1. Ссылка против рамок QuartzCore
  2. Включить поддержку слоя для одного или нескольких из ваших объектов NSView, выполнив одно из следующих действий
    • В вашем СИБЕ файлы, используйте инспектор View Effects, чтобы включить поддержку слоев для ваших представлений. Инспектор отображает флажки для выбранного вида и его подпунктов. Рекомендуется включить поддержку слоя в представлении содержимого вашего окна по возможности
    • Для просмотра, который вы создаете программным способом, вызовите метод setWantsLayer: и передайте значение YES, чтобы указать, что представление должно использовать слои.

После включить поддержку слоя на любой из родителей NSOutlineView, в различные глюки решены.

+0

Спасибо за это! У меня была та же проблема (пользовательский прогрессивный счетчик с использованием слоя), а расширяющиеся/сжимающиеся ячейки не перемещали счетчик. Для меня просто нужно включить поддержку слоев на контурном представлении. После этого все было исправлено. – Kyle

+0

Я рад, что это было полезно для вас! :) Я знаю, что долго искал этот ответ! – Dalzhim

0

Трудно прочитать справочные документы NSOutlineView и найти информацию о повторном использовании ячеек, которая, скорее всего, даст вам припадки здесь.

Возможно, вы смотрели outlineViewItemDidCollapse:, но это бесполезно для нашей проблемы, потому что у него нет указателя на NSView, и это потому, что он старше представлений на основе представления.

Возможно, один полезно отметить, погребенные в протоколе NSOutlineViewDelegate, вниз в разделе, посвященном просмотреть на основе методов NSOutlineView, there is a single mention в пределах outlineView:didRemoveRowView:forRow:, что:

Удаленную rowView могут быть повторно использованы с помощью таблицы, так что любой добавочно вставленные представления должны быть удалены в этот момент.

Другими словами, когда вы вызываете контурный вид makeViewWithIdentifier:owner:-х, для cellView или rowView с определенным ID вы часто получить переработанный вид. Особенно часто из-за краха. Кстати, , что метод от NSTableView суперкласса, и в этой ссылке, есть также this comment:

Этот метод может также возвращать повторно использовать вид с тем же идентификатором, который больше не доступен на экране. Если представление с указанным идентификатором не может быть создано из файла nib или найдено в очереди повторного использования, этот метод возвращает nil.

Таким образом, у вас есть возможность изменить иерархию представлений или свойства niling в didRemoveRowView:forRow. Однако, похороненный в третьей ссылки какао, что для NSView, есть в комментарии к prepareForReuse, this comment:

Этот метод предлагает способ сбросить вид на некоторое начальное состояние, так что он может быть использован повторно. Например, класс NSTableView использует его для подготовки просмотров для повторного использования и тем самым позволяет избежать затрат на создание новых представлений при прокрутке их в виде. Если вы внедряете систему повторного использования в свой собственный код, вы можете вызвать этот метод из своего собственного кода до повторного использования.

Итак, TL; DR, вам необходимо реализовать prepareForReuse.

Соответствующие ссылки (в основном) в суперклассы обоих NSOutlineView и NSTableCellView.

И, FWIW, был similar question here, где, похоже, вопросник говорит о том, что ситуация еще хуже, чем я думаю, в том, что NSOutlineView более креативен за кулисами, чем NSTableView.

В моей собственной работе с набросками и встроенными NSTextViews я видел ужасно ужасные икоты рендеринга, связанные с расширением/скроением/прокруткой, которые, как мне кажется, управляются только методами NSOutlineViewDelegate. На iOS они сделали все, чтобы переименовать makeViewWithIdentifier в более явный dequeueReusableCellViewWithIdentifier.

+0

Я попытался внедрить 'prepareForReuse', как вы предложили, но этого было недостаточно для решения проблемы. Некоторая отладка показала, что метод вызывается при работе с контентом, длиннее видимой области. В другом случае метод просто никогда не используется, что доказывает, что это не может быть решением. Проблема заключается в том, что анимация раскрытия и сглаживания, выполняемая NSOutlineView, неправильно обрабатывает подслои. Я также видел другой вопрос, на который вы указали, но на этот вопрос не был удовлетворительно ответил. – Dalzhim

0

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

По моему опыту, слой, сразу назначенный на представление (в отличие от подслоев), не нуждается в настройках маски, рамки или авторезистировки. Он автоматически делается для отслеживания границ представления.На самом деле, я бы не стал устанавливать эти свойства, на всякий случай, что прерывает автоматическую синхронизацию с ограничениями вида.

Итак, вопрос в том, как вы настраиваете представление для перемещения или изменения размера с помощью своего супервизора? Вы используете автоматическую компоновку? Если да, отключили ли вы его translatesAutoresizingMaskIntoConstraints? Если да для обоих, какие ограничения вы задаете в представлении? Если это не так, как вы позиционировали представление в своем супервизии? Какую рамку вы установили? Кроме того, супервизор сконфигурирован для авторазрешения своих подзонов (возможно, да, поскольку это значение по умолчанию)? Ваше мнение выводит autoresizingMask?

Вы также можете переопределить -setFrameOrigin: и -setFrameSize: в своем обычном классе просмотра и позвонить в супер. Кроме того, добавьте регистрацию, чтобы показать, когда это происходит, и что такое новый прямоугольник кадра. Является ли ваше представление перемещенным, как вы ожидаете, когда вы расширяете или сворачиваете строки?

+0

Ну код, который я показал для TestView, завершен. Вот ссылка на демонстрационный проект Apple OutlineView, к которому я добавил TestView. Этот проект прекрасно работает, пока вы не удалите слой из представления содержимого Window в Application.xib. http://filebin.ca/1zm0kIYSuMNo/OutlineView.zip – Dalzhim

 Смежные вопросы

  • Нет связанных вопросов^_^