Как предотвратить вспышку при вызове drawViewHierarchyInRect: afterScreenUpdates: на iOS 8?

В iOS 8 вызывается вызов UIView

[self drawViewHierarchyInRect:self.bounds afterScreenUpdates:YES];

приводит к 1-кратной вспышке изображения. Вы можете увидеть его в течение секунды секунды на экране. Это происходит только тогда, когда параметр afterScreenUpdates равен YES.

Это мой полный код, чтобы сделать снимок экрана:

UIGraphicsBeginImageContextWithOptions(self.bounds.size, NO, sf);
CGContextRef ctx = UIGraphicsGetCurrentContext();
CGContextSaveGState(ctx);
CGContextConcatCTM(ctx, [self.layer affineTransform]);

if ([self respondsToSelector:@selector(drawViewHierarchyInRect:afterScreenUpdates:)]) { // iOS 7+
    [self drawViewHierarchyInRect:self.bounds afterScreenUpdates:YES];
} else { // iOS 6
    [self.layer renderInContext:ctx];
}

UIImage *image = UIGraphicsGetImageFromCurrentImageContext();

CGContextRestoreGState(ctx);
UIGraphicsEndImageContext();

Есть ли способ обхода?

Ответ 1

Предоставьте изображения запуска 3x, которые будут использоваться в iPhone6 ​​и iPhone6 ​​плюс, и эта проблема исчезнет.

Ответ 2

Здесь возможно обходное решение, которое решило мою проблему.

Используйте CATransaction.completionBlock для вызова UIView drawViewHierarchyInRect: afterScreenUpdates с флагом обновлений экрана, установленным в НЕТ. Я использовал это для решения той же проблемы. Это семантически эквивалентно установке флага в YES в моем случае, так как я только вызываю его после, текущее действие CATransaction завершено, и экран находится в нужном состоянии. Тем не менее, в моем случае, у меня нет анимации, так что это довольно быстро и фиксирует именно то, что я хочу. Если были анимации, это может оказаться неприемлемым.

В моем случае у меня есть представление коллекции, представляющее собой набор файлов. Каждый элемент отображается как моментальный снимок того, как выглядит файл, как только пользователь открывает его. В некоторых файлах пользовательский интерфейс содержит сотни слоев. Когда эти сложные представления были сняты, я получаю черную вспышку экрана; или последнюю/текущую анимацию для частичного повторного запуска. В моем представлении коллекции есть w/в навигационном контроллере, я видел частичные повторы поп-анимации. Я также заметил повторы анимации вращения. Для более простых файлов часто не возникало проблем. Я заметил это на своем iPad Air (iOs 8.1) и на различных симуляторах. Я попробовал поставить приложения и launchImages на место, но они не повлияли.

Вот оригинальный код. Он инициализирует контроллер представления, а затем добавляет представление контроллера в представление утилиты.

UIViewController *vlController = [[ComplicatedViewController alloc]init];
UIView *innerView = vlController.view;
[v addSubview:innerView];
innerView.transform = CGAffineTransformMakeScale(scalar, scalar);
innerView.center = CGRectCenterPoint(v.bounds);
auto sz = v.bounds.size;
innerView.bounds = {{0,0}, {sz.width/scalar, sz.height/scalar}};

UIGraphicsBeginImageContextWithOptions(v.bounds.size, YES, 0);
[v drawViewHierarchyInRect:v.bounds afterScreenUpdates:YES];
UIImage *image = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
[innerView removeFromSuperview];

UIImageView *imageView = [[UIImageView alloc] initWithImage:image];
[v addSubview:imageView];

Новый код просто перемещает нижнюю половину в блок завершения UIView animateWithDuration: завершение. Обратите внимание, что продолжительность анимации UIView равна 0, но, похоже, этот дополнительный цикл обновления обновляет экран с помощью нового пользовательского интерфейса.

UIViewController *vlController = [[ComplicatedViewController alloc]init];
UIView *innerView = vlController.view;
[UIView animateWithDuration:0.0 animations:^{
  [v addSubview:innerView];
  innerView.transform = CGAffineTransformMakeScale(scalar, scalar);
  innerView.center = CGRectCenterPoint(v.bounds);
  auto sz = v.bounds.size;
  innerView.bounds = {{0,0}, {sz.width/scalar, sz.height/scalar}};
} completion:^(BOOL finished) {      
    UIGraphicsBeginImageContextWithOptions(v.bounds.size, YES, 0);
    BOOL drawResult = [v drawViewHierarchyInRect:v.bounds afterScreenUpdates:NO];
    UIImage *image = UIGraphicsGetImageFromCurrentImageContext();
    UIGraphicsEndImageContext();
    [innerView removeFromSuperview];

    [self add:image forFile:v.filename withOrientation:v.orientation];
    UIImageView *imageView = [[UIImageView alloc] initWithImage:image];
    [v addSubview:imageView];
}];