Como posso produzir um efeito semelhante à exibição de desfoque do iOS 7?

219

Estou tentando replicar esse fundo desfocado da tela de exemplo do iOS 7, publicamente lançada pela Apple:

Captura de tela do iOS 7 Control Center

Esta pergunta sugere a aplicação de um filtro de IC ao conteúdo abaixo, mas essa é uma abordagem totalmente diferente. É óbvio que o iOS 7 não captura o conteúdo das visualizações abaixo, por vários motivos:

  1. Fazer alguns testes, capturar uma captura de tela das visualizações abaixo e aplicar um filtro CIGaussianBlur com um raio grande o suficiente para imitar o estilo de desfoque do iOS 7 leva 1-2 segundos, mesmo em um simulador.
  2. A exibição de desfoque do iOS 7 pode desfocar as visualizações dinâmicas, como um vídeo ou animações, sem atraso perceptível.

Alguém pode sugerir quais estruturas eles poderiam estar usando para criar esse efeito e se é possível criar um efeito semelhante com as APIs públicas atuais?

Edit: (from comment) Não sabemos exatamente como a Apple está fazendo isso, mas existem suposições básicas que podemos fazer? Podemos assumir que eles estão usando hardware, certo?

O efeito é independente em cada visualização, de modo que o efeito não saiba realmente o que está por trás dele? Ou deve, com base em como os borrões funcionam, o conteúdo por trás do borrão deve ser levado em consideração?

Se o conteúdo por trás do efeito for relevante, podemos supor que a Apple esteja recebendo um "feed" do conteúdo abaixo e processando-o continuamente com um borrão?

Boneco de neve
fonte
(Acho que podemos supor que a Apple esteja usando GL puro para renderizar as telas iniciais de qualquer maneira. Duvido que estejam abstraindo-o com UIViews e outras coisas que prejudicariam o desempenho, já que é uma parte essencial do sistema operacional)
Dave
Como indiquei nos comentários da minha resposta aqui: stackoverflow.com/a/17048668/19679, eles escreveram o sistema operacional; portanto, é claro que eles terão acesso acelerado ao conteúdo das camadas compostas abaixo da visualização atual. Podemos ver um pouco do que eles podem estar usando na API IOSurface privada: stackoverflow.com/questions/14135215/… . Os borrões gaussianos podem ser feitos muito mais rapidamente do que os casos de borrões gaussianos generalizados se eles tiverem um raio fixo ou usar otimizações interessantes como imagens integrais.
Brad Larson
@BradLarson - Parafraseando Jessica Simpson ... Eu não tenho idéia do que tudo isso significa, mas parece legal como diabos! Mas falando sério, você está dizendo que pode usar uma vista parcialmente transparente com um filtro de desfoque e colocá-la sobre outra vista para obter esse efeito?
sangony
stackoverflow.com/a/25706250/2308190 funcionou perfeitamente para mim na primeira vez que o experimentei e foi conciso
Ben Wheeler

Respostas:

134

Por que se preocupar em replicar o efeito? Basta desenhar uma barra UITool atrás da sua visualização.

myView.backgroundColor = [UIColor clearColor];
UIToolbar* bgToolbar = [[UIToolbar alloc] initWithFrame:myView.frame];
bgToolbar.barStyle = UIBarStyleDefault;
[myView.superview insertSubview:bgToolbar belowSubview:myView];
user2342340
fonte
8
Eu discordo de Crizzwald. Não acho que seja uma boa interpretação das regras de expectativa do que a APple fará.
Andrew Johnson
117
Eu executei essa abordagem por um engenheiro da Apple UIKit esta semana em seu laboratório Tech Talks. Embora ele certamente não endossasse essa abordagem, ele reconheceu a necessidade do efeito e a falta de API pública real para isso, e disse que essa abordagem era a opção "menos maligna" no momento e é razoavelmente segura como está escrita. Especificamente, ele disse que não tente fazer nenhuma animação da frameou transformdesta barra de ferramentas / exibição ou algo assim, ou coisas ruins acontecerão. Ele também sugeriu fortemente arquivar relatórios de erros do Radar sobre isso, para construir um caso internamente para que possamos obter uma API pública real para esse efeito!
smileyborg
44
Interessante ... parece que a conta @ user2342340 foi criada apenas para responder a esta pergunta anonimamente. Faz você se perguntar se isso não é um cargo oficial por alguém que sabe mais do que o resto de nós sobre essas coisas :)
smileyborg
4
Isso não funciona no iPhone 4 executando o iOS 7. É provavelmente porque no iPhone 4, como a GPU está muito baixa, o sistema não adiciona o efeito de desfoque usual a UITabBarsi próprio.
Ayush Goel
2
Como faço para não ser branco? Se eu alterar a cor de fundo da barra de ferramentas, ela não mostrará o desfoque.
Nikita P
64

A Apple lançou o código na WWDC como uma categoria na UIImage que inclui essa funcionalidade. Se você possui uma conta de desenvolvedor, pode pegar a categoria UIImage (e o restante do código de exemplo) acessando este link: https://developer.apple. com / wwdc / schedule / e navegando para a seção 226 e clicando em detalhes. Ainda não brinquei com ele, mas acho que o efeito será muito mais lento no iOS 6, há algumas melhorias no iOS 7 que tornam mais rápida a captura da captura de tela inicial usada como entrada para o desfoque.

Link direto: https://developer.apple.com/downloads/download.action?path=wwdc_2013/wwdc_2013_sample_code/ios_uiimageeffects.zip

FreaknBigPanda
fonte
1
Eu vejo o vídeo, posso assistir, mas não consigo descobrir onde baixar o código de exemplo!
Nathan H
Não vi muita diferença em comparação com uma simples mudança alfa de fundo; talvez seja porque eu sou vídeos exibindo e eles só precisam de mais borrão ...
Jack
37

Na verdade, eu aposto que isso seria bastante simples de conseguir. Provavelmente não funcionaria ou se pareceria exatamente com o que a Apple está acontecendo, mas poderia estar muito próximo.

Primeiro de tudo, você precisa determinar o CGRect do UIView que você apresentará. Depois de determinar que você precisaria apenas pegar uma imagem da parte da interface do usuário para que ela fique embaçada. Algo assim...

- (UIImage*)getBlurredImage {
    // You will want to calculate this in code based on the view you will be presenting.
    CGSize size = CGSizeMake(200,200);

    UIGraphicsBeginImageContext(size);
    [view drawViewHierarchyInRect:(CGRect){CGPointZero, w, h} afterScreenUpdates:YES]; // view is the view you are grabbing the screen shot of. The view that is to be blurred.
    UIImage *image = UIGraphicsGetImageFromCurrentImageContext();
    UIGraphicsEndImageContext();

    // Gaussian Blur
    image = [image applyLightEffect];

    // Box Blur
    // image = [image boxblurImageWithBlur:0.2f];

    return image;
}

Gaussian Blur - Recomendado

Usando a UIImage+ImageEffectscategoria Apple fornecida aqui , você obterá um desfoque gaussiano que se parece muito com o desfoque no iOS 7.

Borrão de caixa

Você também pode usar um desfoque de caixa usando a seguinte boxBlurImageWithBlur:categoria UIImage. Isso é baseado em um algoritmo que você pode encontrar aqui .

@implementation UIImage (Blur)

-(UIImage *)boxblurImageWithBlur:(CGFloat)blur {
    if (blur < 0.f || blur > 1.f) {
        blur = 0.5f;
    }
    int boxSize = (int)(blur * 50);
    boxSize = boxSize - (boxSize % 2) + 1;

    CGImageRef img = self.CGImage;

    vImage_Buffer inBuffer, outBuffer;

    vImage_Error error;

    void *pixelBuffer;

    CGDataProviderRef inProvider = CGImageGetDataProvider(img);
    CFDataRef inBitmapData = CGDataProviderCopyData(inProvider);

    inBuffer.width = CGImageGetWidth(img);
    inBuffer.height = CGImageGetHeight(img);
    inBuffer.rowBytes = CGImageGetBytesPerRow(img);

    inBuffer.data = (void*)CFDataGetBytePtr(inBitmapData);

    pixelBuffer = malloc(CGImageGetBytesPerRow(img) * CGImageGetHeight(img));

    if(pixelBuffer == NULL)
        NSLog(@"No pixelbuffer");

    outBuffer.data = pixelBuffer;
    outBuffer.width = CGImageGetWidth(img);
    outBuffer.height = CGImageGetHeight(img);
    outBuffer.rowBytes = CGImageGetBytesPerRow(img);

    error = vImageBoxConvolve_ARGB8888(&inBuffer, &outBuffer, NULL, 0, 0, boxSize, boxSize, NULL, kvImageEdgeExtend);

    if (error) {
        NSLog(@"JFDepthView: error from convolution %ld", error);
    }

    CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB();
    CGContextRef ctx = CGBitmapContextCreate(outBuffer.data,
                                         outBuffer.width,
                                         outBuffer.height,
                                         8,
                                         outBuffer.rowBytes,
                                         colorSpace,
                                         kCGImageAlphaNoneSkipLast);
    CGImageRef imageRef = CGBitmapContextCreateImage (ctx);
    UIImage *returnImage = [UIImage imageWithCGImage:imageRef];

    //clean up
    CGContextRelease(ctx);
    CGColorSpaceRelease(colorSpace);

    free(pixelBuffer);
    CFRelease(inBitmapData);

    CGImageRelease(imageRef);

    return returnImage;
}

@end

Agora que você está calculando a área da tela para desfocar, passando-a para a categoria de desfoque e recebendo uma UIImage de volta que ficou desfocada, agora resta apenas definir essa imagem desfocada como o fundo da exibição que você apresentará. Como eu disse, isso não será uma combinação perfeita para o que a Apple está fazendo, mas ainda deve parecer bem legal.

Espero que ajude.

Jeremy Fox
fonte
Parece que a cor azul e vermelha da imagem borrada estão alteradas.
Henry
Parece que alguém usou seu código para criar este projeto: github.com/alexdrone/ios-realtimeblur/blob/master/RealTimeBlur/…, mas infelizmente não há atribuição, e eles adicionaram uma declaração de direitos autorais "Todos os direitos reservados" no topo.
precisa
@ Mark, obrigado pela atenção. No entanto, esse algoritmo de desfoque não é meu. Eu já mencionei de onde consegui isso no meu post acima. Como está escrito no meu post "Isso é baseado em um algoritmo que você pode encontrar aqui". com um link para indieambitions.com/idevblogaday/… Definitivamente enviarei uma mensagem a essa pessoa e informarei que estão faltando a atribuição. Obrigado
Jeremy Fox
@ MarkErdmann veja seus próprios arquivos no xcode. Possui "Todos os direitos reservados". É uma coisa genérica que o xcode adiciona. Além disso, o autor adicionou apenas um license.md que diz que está licenciado sob a licença #
Papai Noel
Não use renderInContext, use o novo drawViewHierarchyInRect:ou snapshotView:. A palestra WWDC 216 "Implementando a interface do usuário envolvente no iOS7" alega uma melhoria de desempenho de 5-15x.
precisa saber é
25

O iOS8 respondeu a estas perguntas.

UIVisualEffect

- (instancetype)initWithEffect:(UIVisualEffect *)effect

ou Swift:

init(effect effect: UIVisualEffect)

Adam Waite
fonte
Eu acho que essa solução é inútil até que o iOS 9 seja lançado. A maioria dos aplicativos ainda suporta o iOS 7, e esta solução não é suportada lá.
Dmitry Sobolev
true true, você pode usar esse tipo de coisa por enquanto: github.com/nicklockwood/FXBlurView
Adam Waite
Eu implementei isso com a cadeia de ferramentas Xcode 6 com iOS8 e funciona muito bem. Eu tentei implementar usando a CPU, mas funciona visivelmente mais lento que esse método.
Jon
Por que codificar quando o Xcode fornece no próprio storyboard !!!!! Obrigado @AdamWaite
Mihir Oza
20

Acabei de escrever minha pequena subclasse de UIView que tem capacidade de produzir o iOS 7 nativo blur em qualquer visualização personalizada. Ele usa o UIToolbar, mas de maneira segura para alterar seu quadro, limites, cores e alfa com animação em tempo real.

Entre em contato se notar algum problema.

https://github.com/ivoleko/ILTranslucentView

ILTranslucentVer exemplos

Ivo Leko
fonte
Eu tentei algumas outras abordagens (como adicionar uma barra UITool ou a categoria UIImage + ImageEffects.h da Apple); a sua era a melhor e mais fácil solução. Obrigado!
Yunus Nedim Mehel 24/10
4
Como ele reage ao novo download do iOS 7.0.3? Outras classes que usaram essa técnica não são mais renderizadas corretamente: [
achi
@achi, não notei nenhum problema no iOS 7.0.3.
Ivo Leko
Você sabe se algum aplicativo é animado usando sua abordagem e foi aceito pela Apple?
Brad Goss
Oi pessoal. Sim, o aplicativo que usa essa classe será aprovado pela Apple!
Ivo Leko
10

Há um boato de que os engenheiros da Apple alegaram que, para obter esse desempenho, eles estão lendo diretamente do buffer gpu, o que levanta problemas de segurança e é por isso que ainda não há uma API pública para fazer isso.

Cody C
fonte
6
Se isso é verdade, então essa é - de longe - a pior solução de todos os tempos.
elslooo
2
aaaaaand o borrão é removido do iOS 7.
Código Guru
3
Ele foi removido apenas em dispositivos com problemas de desempenho.
Cody C
24
Este post é a fonte do boato? :)
Jano
11
Esse boato provavelmente é uma besteira. O OpenGL ES 2.0 no iOS permite ler e gravar em framebuffers sem nenhum risco à segurança. O desfoque é feito usando sombreadores GLSL, e é por isso que é executado rapidamente.
bentford
7

Esta é uma solução que você pode ver nos vídeos da WWDC. Você precisa fazer um Gaussian Blur; portanto, a primeira coisa a fazer é adicionar um novo arquivo .m e .h com o código que estou escrevendo aqui; depois, é necessário fazer uma captura de tela, usar o efeito desejado e adicione-o à sua visualização e, em seguida, com o UITable UIView ou o que for transparente, você pode brincar com applyBlurWithRadius. Para arquivar o efeito desejado, essa chamada funciona com qualquer UIImage.

No final, a imagem manchada será o plano de fundo e o restante dos controles acima deverá ser transparente.

Para que isso funcione, você deve adicionar as próximas bibliotecas:

Acelerate.framework, UIKit.framework, CoreGraphics.framework

Espero que você goste.

Feliz codificação.

    //Screen capture.
    UIGraphicsBeginImageContext(self.view.bounds.size);

    CGContextRef c = UIGraphicsGetCurrentContext();
    CGContextTranslateCTM(c, 0, 0);
    [self.view.layer renderInContext:c];

    UIImage* viewImage = UIGraphicsGetImageFromCurrentImageContext();
    viewImage = [viewImage applyLightEffect];

    UIGraphicsEndImageContext();

    //.h FILE
    #import <UIKit/UIKit.h>

    @interface UIImage (ImageEffects)

   - (UIImage *)applyLightEffect;
   - (UIImage *)applyExtraLightEffect;
   - (UIImage *)applyDarkEffect;
   - (UIImage *)applyTintEffectWithColor:(UIColor *)tintColor;

   - (UIImage *)applyBlurWithRadius:(CGFloat)blurRadius tintColor:(UIColor *)tintColor saturationDeltaFactor:(CGFloat)saturationDeltaFactor maskImage:(UIImage *)maskImage;

   @end

    //.m FILE
    #import "cGaussianEffect.h"
    #import <Accelerate/Accelerate.h>
    #import <float.h>


     @implementation UIImage (ImageEffects)


    - (UIImage *)applyLightEffect
    {
        UIColor *tintColor = [UIColor colorWithWhite:1.0 alpha:0.3];
        return [self applyBlurWithRadius:1 tintColor:tintColor saturationDeltaFactor:1.8 maskImage:nil];
    }


    - (UIImage *)applyExtraLightEffect
    {
        UIColor *tintColor = [UIColor colorWithWhite:0.97 alpha:0.82];
        return [self applyBlurWithRadius:1 tintColor:tintColor saturationDeltaFactor:1.8 maskImage:nil];
    }


    - (UIImage *)applyDarkEffect
    {
        UIColor *tintColor = [UIColor colorWithWhite:0.11 alpha:0.73];
        return [self applyBlurWithRadius:1 tintColor:tintColor saturationDeltaFactor:1.8 maskImage:nil];
    }


    - (UIImage *)applyTintEffectWithColor:(UIColor *)tintColor
    {
        const CGFloat EffectColorAlpha = 0.6;
        UIColor *effectColor = tintColor;
        int componentCount = CGColorGetNumberOfComponents(tintColor.CGColor);
        if (componentCount == 2) {
            CGFloat b;
            if ([tintColor getWhite:&b alpha:NULL]) {
                effectColor = [UIColor colorWithWhite:b alpha:EffectColorAlpha];
            }
        }
        else {
            CGFloat r, g, b;
            if ([tintColor getRed:&r green:&g blue:&b alpha:NULL]) {
                effectColor = [UIColor colorWithRed:r green:g blue:b alpha:EffectColorAlpha];
            }
        }
        return [self applyBlurWithRadius:10 tintColor:effectColor saturationDeltaFactor:-1.0 maskImage:nil];
    }


    - (UIImage *)applyBlurWithRadius:(CGFloat)blurRadius tintColor:(UIColor *)tintColor saturationDeltaFactor:(CGFloat)saturationDeltaFactor maskImage:(UIImage *)maskImage
    {
        if (self.size.width < 1 || self.size.height < 1) {
            NSLog (@"*** error: invalid size: (%.2f x %.2f). Both dimensions must be >= 1: %@", self.size.width, self.size.height, self);
            return nil;
        }
        if (!self.CGImage) {
            NSLog (@"*** error: image must be backed by a CGImage: %@", self);
            return nil;
        }
        if (maskImage && !maskImage.CGImage) {
            NSLog (@"*** error: maskImage must be backed by a CGImage: %@", maskImage);
            return nil;
        }

        CGRect imageRect = { CGPointZero, self.size };
        UIImage *effectImage = self;

        BOOL hasBlur = blurRadius > __FLT_EPSILON__;
        BOOL hasSaturationChange = fabs(saturationDeltaFactor - 1.) > __FLT_EPSILON__;
        if (hasBlur || hasSaturationChange) {
            UIGraphicsBeginImageContextWithOptions(self.size, NO, [[UIScreen mainScreen] scale]);
            CGContextRef effectInContext = UIGraphicsGetCurrentContext();
            CGContextScaleCTM(effectInContext, 1.0, -1.0);
            CGContextTranslateCTM(effectInContext, 0, -self.size.height);
            CGContextDrawImage(effectInContext, imageRect, self.CGImage);

            vImage_Buffer effectInBuffer;
            effectInBuffer.data     = CGBitmapContextGetData(effectInContext);
            effectInBuffer.width    = CGBitmapContextGetWidth(effectInContext);
            effectInBuffer.height   = CGBitmapContextGetHeight(effectInContext);
            effectInBuffer.rowBytes = CGBitmapContextGetBytesPerRow(effectInContext);

            UIGraphicsBeginImageContextWithOptions(self.size, NO, [[UIScreen mainScreen] scale]);
            CGContextRef effectOutContext = UIGraphicsGetCurrentContext();
            vImage_Buffer effectOutBuffer;
            effectOutBuffer.data     = CGBitmapContextGetData(effectOutContext);
            effectOutBuffer.width    = CGBitmapContextGetWidth(effectOutContext);
            effectOutBuffer.height   = CGBitmapContextGetHeight(effectOutContext);
            effectOutBuffer.rowBytes = CGBitmapContextGetBytesPerRow(effectOutContext);

            if (hasBlur) {
                CGFloat inputRadius = blurRadius * [[UIScreen mainScreen] scale];
                NSUInteger radius = floor(inputRadius * 3. * sqrt(2 * M_PI) / 4 + 0.5);
                if (radius % 2 != 1) {
                    radius += 1;
                }
                vImageBoxConvolve_ARGB8888(&effectInBuffer, &effectOutBuffer, NULL, 0, 0, radius, radius, 0, kvImageEdgeExtend);
                vImageBoxConvolve_ARGB8888(&effectOutBuffer, &effectInBuffer, NULL, 0, 0, radius, radius, 0, kvImageEdgeExtend);
                vImageBoxConvolve_ARGB8888(&effectInBuffer, &effectOutBuffer, NULL, 0, 0, radius, radius, 0, kvImageEdgeExtend);
            }
            BOOL effectImageBuffersAreSwapped = NO;
            if (hasSaturationChange) {
                CGFloat s = saturationDeltaFactor;
                CGFloat floatingPointSaturationMatrix[] = {
                    0.0722 + 0.9278 * s,  0.0722 - 0.0722 * s,  0.0722 - 0.0722 * s,  0,
                    0.7152 - 0.7152 * s,  0.7152 + 0.2848 * s,  0.7152 - 0.7152 * s,  0,
                    0.2126 - 0.2126 * s,  0.2126 - 0.2126 * s,  0.2126 + 0.7873 * s,  0,
                                  0,                    0,                    0,  1,
                };
                const int32_t divisor = 256;
                NSUInteger matrixSize = sizeof(floatingPointSaturationMatrix)/sizeof(floatingPointSaturationMatrix[0]);
                int16_t saturationMatrix[matrixSize];
                for (NSUInteger i = 0; i < matrixSize; ++i) {
                    saturationMatrix[i] = (int16_t)roundf(floatingPointSaturationMatrix[i] * divisor);
                }
                if (hasBlur) {
                    vImageMatrixMultiply_ARGB8888(&effectOutBuffer, &effectInBuffer, saturationMatrix, divisor, NULL, NULL, kvImageNoFlags);
                    effectImageBuffersAreSwapped = YES;
                }
                else {
                    vImageMatrixMultiply_ARGB8888(&effectInBuffer, &effectOutBuffer, saturationMatrix, divisor, NULL, NULL, kvImageNoFlags);
                }
            }
            if (!effectImageBuffersAreSwapped)
                effectImage = UIGraphicsGetImageFromCurrentImageContext();
            UIGraphicsEndImageContext();

            if (effectImageBuffersAreSwapped)
                effectImage = UIGraphicsGetImageFromCurrentImageContext();
            UIGraphicsEndImageContext();
        }

        UIGraphicsBeginImageContextWithOptions(self.size, NO, [[UIScreen mainScreen] scale]);
        CGContextRef outputContext = UIGraphicsGetCurrentContext();
        CGContextScaleCTM(outputContext, 1.0, -1.0);
        CGContextTranslateCTM(outputContext, 0, -self.size.height);

        CGContextDrawImage(outputContext, imageRect, self.CGImage);

        if (hasBlur) {
            CGContextSaveGState(outputContext);
            if (maskImage) {
                CGContextClipToMask(outputContext, imageRect, maskImage.CGImage);
            }
            CGContextDrawImage(outputContext, imageRect, effectImage.CGImage);
            CGContextRestoreGState(outputContext);
        }

        if (tintColor) {
            CGContextSaveGState(outputContext);
            CGContextSetFillColorWithColor(outputContext, tintColor.CGColor);
            CGContextFillRect(outputContext, imageRect);
            CGContextRestoreGState(outputContext);
        }

        UIImage *outputImage = UIGraphicsGetImageFromCurrentImageContext();
        UIGraphicsEndImageContext();

        return outputImage;
    }
Marco Antonio Uzcategui Pescoz
fonte
7

Você pode encontrar sua solução na DEMO da apple nesta página: WWDC 2013 , descubra e faça o download do código de exemplo UIImageEffects.

Depois, com o código de Jeremy Fox. Eu mudei para

- (UIImage*)getDarkBlurredImageWithTargetView:(UIView *)targetView
{
    CGSize size = targetView.frame.size;

    UIGraphicsBeginImageContext(size);
    CGContextRef c = UIGraphicsGetCurrentContext();
    CGContextTranslateCTM(c, 0, 0);
    [targetView.layer renderInContext:c]; // view is the view you are grabbing the screen shot of. The view that is to be blurred.
    UIImage *image = UIGraphicsGetImageFromCurrentImageContext();
    UIGraphicsEndImageContext();
    return [image applyDarkEffect];
}

Espero que isso ajude você.

Senry
fonte
7

Aqui está uma maneira realmente fácil de fazer isso: https://github.com/JagCesar/iOS-blur

Basta copiar a camada do UIToolbar e pronto, o AMBlurView faz isso por você. Ok, não é tão embaçado quanto o centro de controle, mas é embaçado o suficiente.

Lembre-se de que o iOS7 está sob NDA.

Simon
fonte
6

Toda resposta aqui está usando o vImageBoxConvolve_ARGB8888. Essa função é muito, muito lenta, tudo bem, se o desempenho não for um requisito de alta prioridade, mas se você o estiver usando para fazer a transição entre dois View Controllers (por exemplo), essa abordagem significa vezes mais de 1 segundo ou talvez mais, isso é muito ruim para a experiência do usuário do seu aplicativo.

Se você preferir deixar todo esse processamento de imagem para a GPU (você deveria), poderá obter um efeito muito melhor e também tempos impressionantes em torno de 50ms (supondo que você tenha um tempo de 1 segundo na primeira abordagem), então vamos fazê-lo .

Primeiro faça o download do GPUImage Framework (BSD Licensed) aqui .

Em seguida, adicione as seguintes classes (.m e .h) da GPUImage (não tenho certeza de que sejam o mínimo necessário apenas para o efeito de desfoque)

  • GPUImage.h
  • GPUImageAlphaBlendFilter
  • GPUImageFilter
  • GPUImageFilterGroup
  • GPUImageGaussianBlurPositionFilter
  • GPUImageGaussianSelectiveBlurFilter
  • GPUImageLuminanceRangeFilter
  • GPUImageOutput
  • GPUImageTwoInputFilter
  • GLProgram
  • GPUImageBoxBlurFilter
  • GPUImageGaussianBlurFilter
  • GPUImageiOSBlurFilter
  • GPUImageSaturationFilter
  • GPUImageSolidColorGenerator
  • GPUImageTwoPassFilter
  • GPUImageTwoPassTextureSamplingFilter

  • iOS / GPUImage-Prefix.pch

  • iOS / GPUImageContext
  • iOS / GPUImageMovieWriter
  • iOS / GPUImagePicture
  • iOS / GPUImageView

Em seguida, crie uma categoria no UIImage, que adicionará um efeito de desfoque a um UIImage existente:

#import "UIImage+Utils.h"

#import "GPUImagePicture.h"
#import "GPUImageSolidColorGenerator.h"
#import "GPUImageAlphaBlendFilter.h"
#import "GPUImageBoxBlurFilter.h"

@implementation UIImage (Utils)

- (UIImage*) GPUBlurredImage
{
    GPUImagePicture *source =[[GPUImagePicture alloc] initWithImage:self];

    CGSize size = CGSizeMake(self.size.width * self.scale, self.size.height * self.scale);

    GPUImageBoxBlurFilter *blur = [[GPUImageBoxBlurFilter alloc] init];
    [blur setBlurRadiusInPixels:4.0f];
    [blur setBlurPasses:2.0f];
    [blur forceProcessingAtSize:size];
    [source addTarget:blur];

    GPUImageSolidColorGenerator * white = [[GPUImageSolidColorGenerator alloc] init];

    [white setColorRed:1.0f green:1.0f blue:1.0f alpha:0.1f];
    [white forceProcessingAtSize:size];

    GPUImageAlphaBlendFilter * blend = [[GPUImageAlphaBlendFilter alloc] init];
    blend.mix = 0.9f;

    [blur addTarget:blend];
    [white addTarget:blend];

    [blend forceProcessingAtSize:size];
    [source processImage];

    return [blend imageFromCurrentlyProcessedOutput];
}

@end

E por último, adicione as seguintes estruturas ao seu projeto:

AVFoundation CoreMedia CoreVideo OpenGLES

Sim, me diverti com essa abordagem muito mais rápida;)

D33pN16h7
fonte
4

Você pode tentar usar meu modo de exibição personalizado, que tem a capacidade de desfocar o fundo. Ele faz isso fingindo tirar um instantâneo do fundo e desfocá-lo, assim como o do código WWDC da Apple. É muito simples de usar.

Também fiz algumas melhorias para fingir o borrão dinâmico sem perder o desempenho. O plano de fundo da minha visualização é um scrollView que rola com a visualização, fornecendo assim o efeito de desfoque para o restante da superview.

Veja o exemplo e o código no meu GitHub

Byte
fonte