CALayer Live Resize Низкая производительность - PullRequest
2 голосов
/ 28 ноября 2011

У меня есть пользовательский интерфейс, в котором содержимое View NSCollectionViewItem рисуется программно через CALayers.Я использую CAConstraintLayoutManager, чтобы сохранить согласованность расположения подслоев при изменении размера, но при этом у меня очень низкая производительность.Кажется, что изменение размера окна, которое вызывает изменение размера двух CATextLayer с, чтобы они соответствовали ширине корневого слоя, и изменение положения одного CATextLayer, чтобы оно оставалось выровненным по правому краю, заставляет приложение тратить большую частьвремя выполнения функции CGSScanConvolveAndIntegrateRGB (я использовал инструмент Time Profiler).

Самый «дорогой» слой (тот, который вызывает наибольшее заикание, даже если отображается только один) - это обернутая многострочная CATextLayer.Я абсолютно не представляю, как повысить производительность (я пытался не использовать CAConstraintLayoutManager и работать с выравниванием слоев, но получаю то же самое).У кого-нибудь была эта проблема?Есть ли способ обойти это?

PS: Я подклассифицировал менеджер раскладки и отключил все анимации во время выполнения - (void)layoutSublayersOfLayer:(CALayer *)layer, установив YES на kCATransactionDisableActions в CATransaction, но это не такКажется, что помогает.

Редактировать: Я отключил сглаживание шрифтов для текстовых слоев, и производительность немного увеличилась (очень немного), но он тратит огромное количество времени в _ZL9view_drawP7_CAViewdPK11CVTimeStampb (это то, что вызывается потоком драйвера ATI Radeon, я полагаю).

1 Ответ

1 голос
/ 29 ноября 2011

Я решил это. Вид. Это все еще кажется мне грязным хаком, но я не мог понять, как заставить setNeedsDisplayInRect работать, поэтому я закончил так:

  1. В делегате NSWindow:

    - (void) windowWillStartLiveResize: (NSNotification *) уведомление { [[NSNotificationCenter defaultCenter] postNotificationName: @ "beginResize" object: nil]; }

    - (void) windowDidEndLiveResize: (NSNotification *) уведомление { [[NSNotificationCenter defaultCenter] postNotificationName: @ "endResize" object: nil];
    }

  2. В моем пользовательском просмотре эти два уведомления вызывают соответственно селекторы -(void)beginResize и -(void)endResize. Первый устанавливает для переменной BOOL inLiveResize значение YES, а для второго - значение NO и снова вызывает setFrameSize с новым размером кадра.

  3. Я переопределил (переопределил? Не носитель английского языка, извините) метод -(void)setFrameSize:(NSSize)newSize, подобный этому:

    -(void)setFrameSize:(NSSize)newSize 
    {        
        if (inLiveResize) {
            NSRect scrollFrame = [[[self superview] enclosingScrollView] documentVisibleRect];
    
            BOOL condition1 = (self.frame.origin.y > (scrollFrame.origin.y - self.frame.size.height));
            BOOL condition2 = (self.frame.origin.y < (scrollFrame.origin.y + scrollFrame.size.height + self.frame.size.height));
    
            if (condition1 && condition2)
                [super setFrameSize:newSize];
        }
        else {
            [super setFrameSize:newSize]; }}
    

Вот и все. Таким образом, только видимые виды изменяют размер в реальном времени с окном, в то время как другие перерисовываются в конце операции. Это работает, но мне не нравится, насколько это «грязно», я уверен, что есть более элегантный, встроенный (ish) способ сделать это с помощью метода setNeedsDisplayInRect. Я буду исследовать больше.

...