iOS / Core-Animation: настройка производительности

У меня есть приложение, работающее на моем iPad. Но оно работает очень плохо - я получаю ниже 15 кадров в секунду. Может ли кто-нибудь помочь мне оптимизировать?

По сути, это колесо (производное от UIView), содержащее 12 кнопок (производное от UIControl). image of control

Когда пользователь вращает его, кнопки динамически расширяются и сжимаются (например, кнопка в позиции 12 часов всегда должна быть самой большой).

Итак, мое колесо содержит:

- (void) displayLinkIsCallingBack: (CADisplayLink *) dispLink 
{
    :
    // using CATransaction like this goes from 14fps to 19fps
    [CATransaction begin];
    [CATransaction setDisableActions: YES];

    // NEG, as coord system is flipped/fucked
    self.transform = CGAffineTransformMakeRotation(-thetaWheel);

    [CATransaction commit];

    if (BLA)
        [self rotateNotch: direction];  
}

… который рассчитывается на основе недавнего касания введите новое вращение колеса. Здесь уже есть одна проблема производительности, которую я рассматриваю в отдельном потоке: iOS Core-Animation: Проблемы производительности с матрицами преобразования CATransaction / Interpolating

Эта процедура также проверяет, завершило ли колесо еще один поворот на 1/12, и если да, указывает всем 12 кнопкам изменить размер:

// Wheel.m
- (void) rotateNotch: (int) direction
{
    for (int i=0; i < [self buttonCount] ; i++)
    {
            CustomButton * b = (CustomButton *) [self.buttons objectAtIndex: i];

    // Note that b.btnSize is a dynamic property which will calculate
    // the desired button size based on the button index and the wheels rotation.
            [b resize: b.btnSize];
    }
}

Теперь о фактическом коде изменения размера, в button.m:

// Button.m

- (void) scaleFrom: (float) s_old
                to: (float) s_new
              time: (float) t
{
    CABasicAnimation * scaleAnimation = [CABasicAnimation animationWithKeyPath: @"transform.scale"];

    [scaleAnimation setDuration:  t ];
    [scaleAnimation setFromValue:  (id) [NSNumber numberWithDouble: s_old] ];
    [scaleAnimation setToValue:  (id) [NSNumber numberWithDouble: s_new] ];
    [scaleAnimation setTimingFunction:  [CAMediaTimingFunction functionWithName: kCAMediaTimingFunctionEaseOut] ];
    [scaleAnimation setFillMode: kCAFillModeForwards];
    scaleAnimation.removedOnCompletion = NO;

    [self.contentsLayer addAnimation: scaleAnimation 
                              forKey: @"transform.scale"];

    if (self.displayShadow && self.shadowLayer)
        [self.shadowLayer addAnimation: scaleAnimation 
                                forKey: @"transform.scale"];    

    size = s_new;
}

// - - - 

- (void) resize: (float) newSize
{
    [self scaleFrom: size
                 to: newSize
               time: 1.];
}

Интересно, связана ли проблема с накладными расходами на несколько операций transform.scale, стоящих в очереди - каждая кнопка изменение размера занимает целую секунду, и если я быстро вращаю колесо, я могу вращать пару оборотов в секунду; это означает, что размер каждой кнопки изменяется 24 раза в секунду.

** создание слоя кнопки **

Последний кусок головоломки, который я думаю, - это взглянуть на ContentLayer кнопки. но я пробовал

contentsLayer.setRasterize = YES;

, который должен эффективно сохранять его как растровое изображение. таким образом, с этой настройкой код фактически динамически изменяет размер 12 растровых изображений.

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

Это бесполезно: мне в конечном итоге нужно поместить текстовый слой внутри каждой кнопки, и это еще больше снизит производительность ( ... если я не использую параметр .setRasterize выше, в этом случае он должен быть таким же).

Я что-то делаю не так! но что?

РЕДАКТИРОВАТЬ: вот код, отвечающий за создание слоя содержимого кнопки (т.е. формы с тенью):

- (CALayer *) makeContentsLayer
{
    CAShapeLayer * shapeOutline = [CAShapeLayer layer];
    shapeOutline.path = self.pOutline;

    CALayer * contents = [CALayer layer];

    // get the smallest rectangle centred on (0,0) that completely contains the button
    CGRect R = CGRectIntegral(CGPathGetPathBoundingBox(self.pOutline)); 
    float xMax = MAX(abs(R.origin.x), abs(R.origin.x+R.size.width));
    float yMax = MAX(abs(R.origin.y), abs(R.origin.y+R.size.height));
    CGRect S = CGRectMake(-xMax, -yMax, 2*xMax, 2*yMax);
    contents.bounds = S; 

    contents.shouldRasterize = YES; // try NO also

    switch (technique)
    {
        case kMethodMask:
            // clip contents layer by outline (outline centered on (0, 0))
            contents.backgroundColor = self.clr; 
            contents.mask = shapeOutline;
            break;

        case kMethodComposite:
            shapeOutline.fillColor = self.clr;
            [contents addSublayer: shapeOutline];
            self.shapeLayer = shapeOutline;
            break;

        default:
            break;
    }

    if (NO)
        [self markPosition: CGPointZero
                   onLayer: contents ];

    //[self refreshTextLayer];

    //[contents addSublayer: self.shapeLayerForText];

    return contents;
}

как вы можете видеть, я пробую все возможные подходы, я пробую два метода для создавая форму, и отдельно я переключаю .shouldRasterize

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

РЕДАКТИРОВАТЬ: Теперь я попытался отключить динамическое изменение размера, пока колесо не установится в новое положение, и установив wheel.setRasterize = YES. поэтому он эффективно вращает один предварительно отрендеренный UIView (который, по общему признанию, занимает большую часть экрана) под пальцем (что он с радостью делает @ ~ 60 кадров в секунду), пока колесо не остановится, после чего он выполняет эту медленную анимацию изменения размера ( @

Хотя это дает приемлемый результат, кажется безумием, что мне приходится жертвовать своим дизайном пользовательского интерфейса таким образом. Я уверен, что что-то делаю неправильно.

РЕДАКТИРОВАТЬ: Я просто в качестве эксперимента попытался изменить размер кнопок вручную; т.е. поместите обратный вызов ссылки отображения в каждой кнопке и динамически вычислите ожидаемый размер данного кадра, явно отключите анимацию с помощью CATransaction, так же, как я сделал с колесом, установите новую матрицу преобразования (масштабное преобразование, созданное из ожидаемого размера). к этому я установил слой содержимого кнопок shouldRasterize = YES. поэтому нужно просто масштабировать 12 растровых изображений в каждом кадре на один UIView, который сам вращается. что удивительно, это очень медленно, даже симулятор останавливается. Это определенно в 10 раз медленнее, чем при автоматическом использовании базовой анимации » s функция анимации.

16
задан Community 23 May 2017 в 11:54
поделиться