Core Animation Производительность анимации маски CALayer

Мы хотели использовать UITabBar в нашем приложении для iPhone, но с одним исключением: у нас есть кнопка «синхронизировать», которую я хотел вращать во время выполнения операции синхронизации.

alt text

К сожалению, это означало необходимость создания настраиваемой панели вкладок, но это ни здесь, ни там: анимация, которую я реализовал с помощью Core Animation, выглядит потрясающе. Проблема в том, что во время анимации она отрицательно влияет на производительность всего остального, использующего анимацию на экране: прокрутка UITableView, панорамирование MKMapView, выпадение булавок и т. Д. Моим тестовым устройством является iPhone 4.

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

// Inside a UIView subclass' init method...

// Create the mask layer by settings its contents as our PNG icon.
CALayer *maskLayer = [CALayer layer];
maskLayer.frame = CGRectMake(0, 0, 31, 31);
maskLayer.contentsGravity = kCAGravityCenter;
maskLayer.contentsScale = [[UIScreen mainScreen] scale];
maskLayer.rasterizationScale = [[UIScreen mainScreen] scale];
maskLayer.contents = (id)symbolImage.CGImage;
maskLayer.shouldRasterize = YES;
maskLayer.opaque = YES;

fgLayer = [[CALayer layer] retain];
fgLayer.frame = self.layer.frame;
fgLayer.backgroundColor = [UIColor colorWithImageNamed:@"tabbar-normal-bg.png"].CGColor;
fgLayer.mask = maskLayer; // Apply the mask
fgLayer.shouldRasterize = YES;
fgLayer.opaque = YES;

[self.layer addSublayer:fgLayer];

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

Чтобы анимировать, я просто вращаю слой маски:

- (void)startAnimating {
    CABasicAnimation* animation = [CABasicAnimation animationWithKeyPath: @"transform"];
    CATransform3D transform = CATransform3DMakeRotation(RADIANS(179.9), 0.0, 0.0, 1.0);
    animation.toValue = [NSValue valueWithCATransform3D:transform];
    animation.duration = 5;
    animation.repeatCount = 10000;
    animation.removedOnCompletion = YES;
    [fgLayer.mask addAnimation:animation forKey:@"rotate"]; // Add animation to the mask
}

Так что все это отлично работает, за исключением производительности. Вы можете видеть, что я уже пробовал советы, которые появлялись в Google по поводу растеризации слоев / придания им непрозрачности - не помогло.

Думаю, я определил, что слой маски является виновником. Когда я вынимаю слой маски и просто вращаю fgLayer вместо его маски, производительность прекрасна, хотя это определенно не тот эффект, на который я собираюсь:

alt text

Производительность такая же плохая, как и раньше если я поверну fgLayer вместо маски , в то время как применяется маска.

Таким образом, если нужно перекомпоновывать маску, каждый кадр анимации замедляется, есть ли другие методы, которые я могу использовать для достижения аналогичного эффекта, который будет иметь лучшую производительность? Используете путь вместо изображения для слоя маски? Или мне придется перейти на OpenGL или что-то еще, чтобы получить хорошую производительность?

ОБНОВЛЕНИЕ: еще больше усиливает идею о том, что маска - это замедление, мой коллега предложил попытаться повернуть CALayer только с изображением в качестве содержимого - так похоже на мой пример выше без маски - и производительность в этом случае также была хорошей. Так что я действительно могу сделать только такой сплошной цвет (без градиента), но это может быть хорошим промежуточным решением. Я все равно хотел бы добиться хорошей производительности при вращении маски, поэтому предложения приветствуются :)

20
задан Brent Dillingham 23 December 2010 в 17:42
поделиться