Comment puis-je produire un effet similaire à la vue floue iOS 7?

219

J'essaie de reproduire cet arrière-plan flou à partir de l'écran d'exemple iOS 7 publié par Apple:

Capture d'écran du centre de contrôle iOS 7

Cette question suggère d'appliquer un filtre CI au contenu ci-dessous, mais c'est une approche complètement différente. Il est évident qu'iOS 7 ne capture pas le contenu des vues ci-dessous, pour de nombreuses raisons:

  1. Faire des tests approximatifs, capturer une capture d'écran des vues ci-dessous et appliquer un filtre CIGaussianBlur avec un rayon suffisamment grand pour imiter le style de flou d'iOS 7 prend 1-2 secondes, même sur un simulateur.
  2. La vue de flou iOS 7 est capable de flouter des vues dynamiques, telles qu'une vidéo ou des animations, sans décalage notable.

Quelqu'un peut-il émettre l'hypothèse des cadres qu'ils pourraient utiliser pour créer cet effet, et s'il est possible de créer un effet similaire avec les API publiques actuelles?

Éditer: (du commentaire) Nous ne savons pas exactement comment Apple le fait, mais y a-t-il des hypothèses de base que nous pouvons faire? Nous pouvons supposer qu'ils utilisent du matériel, non?

L'effet est-il autonome dans chaque vue, de sorte que l'effet ne sait pas réellement ce qu'il y a derrière? Ou, en fonction du fonctionnement du flou, le contenu derrière le flou doit-il être pris en considération?

Si le contenu derrière l'effet est pertinent, peut-on supposer qu'Apple reçoit un "flux" du contenu ci-dessous et le rend continuellement avec un flou?

Bonhomme de neige
la source
(Je pense que nous pouvons supposer que Apple utilise du GL pur pour rendre les écrans d'accueil de toute façon. Je doute qu'ils l'abstraient avec UIViews et d'autres choses qui dégraderaient les performances, car c'est un élément clé du système d'exploitation)
Dave
Comme je l'ai indiqué dans les commentaires de ma réponse ici: stackoverflow.com/a/17048668/19679, ils ont écrit le système d'exploitation, donc bien sûr, ils auront un accès accéléré au contenu des couches composées sous la vue actuelle. Nous pouvons voir certains de ce qu'ils pourraient utiliser dans l'API IOSurface privée: stackoverflow.com/questions/14135215/… . Les flous gaussiens peuvent être rendus beaucoup plus rapides que les cas de flou gaussien généralisés s'ils ont un rayon fixe, ou même utilisent des optimisations intéressantes comme des images intégrales.
Brad Larson
@BradLarson - Pour paraphraser Jessica Simpson ... Je n'ai aucune idée de ce que cela signifie, mais ça a l'air cool! Mais sérieusement, dites-vous que vous pouvez utiliser une vue partiellement transparente avec un filtre de flou et la placer sur une autre vue pour obtenir cet effet?
sangony
stackoverflow.com/a/25706250/2308190 a parfaitement fonctionné pour moi la première fois que je l'ai essayé, et a été concis
Ben Wheeler

Réponses:

134

Pourquoi prendre la peine de reproduire l'effet? Dessinez simplement une barre d'outils UIT derrière votre vue.

myView.backgroundColor = [UIColor clearColor];
UIToolbar* bgToolbar = [[UIToolbar alloc] initWithFrame:myView.frame];
bgToolbar.barStyle = UIBarStyleDefault;
[myView.superview insertSubview:bgToolbar belowSubview:myView];
user2342340
la source
8
Je ne suis pas d'accord avec crizzwald. Je ne pense pas que ce soit une bonne interprétation des règles d'attente de ce que fera APple.
Andrew Johnson
117
J'ai dirigé cette approche par un ingénieur Apple UIKit cette semaine dans leur laboratoire Tech Talks. Bien qu'il ne souscrirait certainement pas à cette approche, il a reconnu la nécessité de l'effet et le manque de véritable API publique pour cela, et a déclaré que cette approche était l'option "la moins mauvaise" pour le moment et qu'elle était assez sûre telle qu'elle était écrite. Plus précisément, il a dit de ne pas essayer de faire des animations de la frameou transformde cette barre d'outils / vue ou quelque chose comme ça, sinon de mauvaises choses se produiront. Il a également fortement suggéré de déposer des rapports de bogues Radar à ce sujet, pour construire un cas en interne afin que nous puissions obtenir une véritable API publique pour cet effet!
smileyborg
44
Intéressant ... il semble que le compte @ user2342340 a été créé juste pour répondre à cette question de manière anonyme. Vous vous demandez si ce n'est pas un message non officiel de quelqu'un qui en sait plus que nous sur ces choses :)
smileyborg
4
Cela ne fonctionne pas sur l'iPhone 4 fonctionnant sous iOS 7. C'est probablement parce que sur l'iPhone 4, puisque la puissance du GPU est trop faible, le système n'ajoute pas l'effet de flou habituel à lui- UITabBarmême.
Ayush Goel
2
Comment le rendre non blanc? Si je change la couleur d'arrière-plan de la barre d'outils, elle ne montre pas le flou.
Nikita P
64

Apple a publié du code sur WWDC en tant que catégorie sur UIImage qui inclut cette fonctionnalité.Si vous avez un compte de développeur, vous pouvez récupérer la catégorie UIImage (et le reste de l'exemple de code) en allant sur ce lien: https://developer.apple. com / wwdc / horaire / et en parcourant la section 226 et en cliquant sur les détails. Je n'ai pas encore joué avec mais je pense que l'effet sera beaucoup plus lent sur iOS 6, il y a quelques améliorations à iOS 7 qui rendent la capture d'écran initiale qui est utilisée comme entrée pour le flou beaucoup plus rapide.

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

FreaknBigPanda
la source
1
Je vois la vidéo, je peux la regarder, mais je ne sais pas où télécharger l'exemple de code!
Nathan H
Je n'ai pas vu beaucoup de différence par rapport à un simple changement alpha en arrière-plan; c'est peut-être parce que j'affiche des vidéos et qu'elles ont juste besoin de plus de flou ...
Ja͢ck
37

En fait, je parierais que ce serait assez simple à réaliser. Il ne fonctionnerait probablement pas ou ne ressemblerait pas exactement à ce qui se passe Apple, mais pourrait être très proche.

Tout d'abord, vous devez déterminer le CGRect de l'UIView que vous présenterez. Une fois que vous avez déterminé que vous auriez juste besoin de saisir une image de la partie de l'interface utilisateur afin qu'elle puisse être floue. Quelque chose comme ça...

- (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;
}

Flou gaussien - Recommandé

En utilisant la UIImage+ImageEffectscatégorie Apple fournie ici , vous obtiendrez un flou gaussien qui ressemble beaucoup au flou dans iOS 7.

Box Blur

Vous pouvez également utiliser un flou de boîte en utilisant la boxBlurImageWithBlur:catégorie UIImage suivante . Ceci est basé sur un algorithme que vous pouvez trouver ici .

@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

Maintenant que vous calculez la zone d'écran à rendre floue, la passez dans la catégorie flou et recevez un retour UIImage flou, il ne reste plus qu'à définir cette image floue comme arrière-plan de la vue que vous allez présenter. Comme je l'ai dit, cela ne correspondra pas parfaitement à ce que fait Apple, mais cela devrait toujours être plutôt cool.

J'espère que ça aide.

Jeremy Fox
la source
Il semble que la couleur bleue et la couleur rouge de l'image floue soient inversées.
Henry
Il semble que quelqu'un ait utilisé votre code pour créer ce projet: github.com/alexdrone/ios-realtimeblur/blob/master/RealTimeBlur/… mais malheureusement il n'y a pas d'attribution, et ils ont ajouté une déclaration de copyright "Tous droits réservés" au sommet.
Mark Erdmann
@Mark, merci pour l'avertissement. Cependant, cet algorithme de flou n'est pas le mien. J'ai déjà mentionné d'où je l'ai obtenu dans mon message ci-dessus. Comme il est dit dans mon article "Ceci est basé sur un algorithme que vous pouvez trouver ici." avec un lien vers indieambitions.com/idevblogaday/… Je vais certainement envoyer un message à cette personne et lui faire savoir qu'il lui manque une attribution. Merci
Jeremy Fox
@MarkErdmann jetez un œil à vos propres fichiers dans xcode. Il a "Tous droits réservés". C'est une chose générique que xcode ajoute. De plus, l'auteur a ajouté juste ajouté un license.md qui dit qu'il a été écouté sous la mit lisence
Père Noël
N'utilisez pas renderInContext, utilisez le nouveau drawViewHierarchyInRect:ou snapshotView:. Discours de la WWDC 216 "Implémentation de l'interface utilisateur engageante sur iOS7" revendique une amélioration des performances de 5 à 15 fois.
bcattle
25

iOS8 a répondu à ces questions.

UIVisualEffect

- (instancetype)initWithEffect:(UIVisualEffect *)effect

ou Swift:

init(effect effect: UIVisualEffect)

Adam Waite
la source
Je suppose que cette solution est pratiquement inutile jusqu'à la sortie d'iOS 9. La majorité des applications prennent toujours en charge iOS 7, et cette solution n'est pas prise en charge là-bas.
Dmitry Sobolev,
vrai vrai, vous pouvez utiliser ce genre de chose pour l'instant: github.com/nicklockwood/FXBlurView
Adam Waite
J'ai implémenté cela avec la chaîne d'outils Xcode 6 avec iOS8, et cela fonctionne très bien. J'ai essayé de l'implémenter en utilisant le CPU, mais fonctionne sensiblement plus lentement que cette méthode.
Jon
Pourquoi coder quand Xcode fournit dans le storyboard lui-même !!!!! Merci @AdamWaite
Mihir Oza
20

Je viens d'écrire ma petite sous-classe d'UIView qui a la capacité de produire un flou iOS 7 natif sur n'importe quelle vue personnalisée. Il utilise UIToolbar mais de manière sûre pour changer son cadre, ses limites, sa couleur et son alpha avec une animation en temps réel.

Veuillez me prévenir si vous remarquez des problèmes.

https://github.com/ivoleko/ILTranslucentView

Exemples ILTranslucentView

Ivo Leko
la source
J'ai essayé d'autres approches (comme l'ajout d'une barre d'outils UIT ou la catégorie UIImage + ImageEffects.h d'Apple); votre solution était la meilleure et la plus simple. Merci!
Yunus Nedim Mehel
4
Comment réagit-il au nouveau téléchargement d'iOS 7.0.3? Les autres classes qui ont utilisé cette technique ne s'affichent plus correctement: [
achi
@achi, je n'ai remarqué aucun problème avec iOS 7.0.3.
Ivo Leko
Savez-vous si des applications animées à l'aide de votre approche ont été acceptées par Apple?
Brad Goss
Salut les gars. Oui, l'application qui utilise cette classe sera approuvée par Apple!
Ivo Leko
10

Il y a une rumeur selon laquelle les ingénieurs d'Apple prétendent que pour rendre cela performant, ils lisent directement la mémoire tampon du processeur graphique, ce qui pose des problèmes de sécurité.C'est pourquoi il n'y a pas encore d'API publique pour le faire.

Cody C
la source
6
Si cela est vrai, c'est - et de loin - la pire solution jamais.
elslooo
2
aaaaa et le flou est supprimé d'iOS 7.
Code Guru
3
Il a été supprimé uniquement sur les appareils qui rencontraient des problèmes de performances.
Cody C
24
Ce post est-il à l'origine de la rumeur? :)
Jano
11
Cette rumeur est probablement superficielle. OpenGL ES 2.0 sur iOS vous permet de lire et d'écrire dans des tampons d'images sans aucun risque de sécurité. Le flou se fait à l'aide de shaders GLSL, c'est pourquoi il fonctionne rapidement.
bentford
7

C'est une solution que vous pouvez voir dans les vidios de la WWDC. Vous devez faire un flou gaussien, donc la première chose que vous devez faire est d'ajouter un nouveau fichier .m et .h avec le code que j'écris ici, puis vous devez faire et faire une capture d'écran, utiliser l'effet souhaité et ajoutez-le à votre vue, puis à votre UITable UIView ou à tout ce qui doit être transparent, vous pouvez jouer avec applyBlurWithRadius, pour archiver l'effet souhaité, cet appel fonctionne avec n'importe quel UIImage.

À la fin, l'image estompée sera l'arrière-plan et les autres commandes ci-dessus doivent être transparentes.

Pour que cela fonctionne, vous devez ajouter les bibliothèques suivantes:

Acelerate.framework, UIKit.framework, CoreGraphics.framework

J'espère que tu aimes.

Codage heureux.

    //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
la source
7

Vous pouvez trouver votre solution dans DEMO d'Apple sur cette page: WWDC 2013 , découvrez et téléchargez l'exemple de code UIImageEffects.

Puis avec le code de @Jeremy Fox. Je l'ai changé en

- (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];
}

J'espère que ceci vous aidera.

Senry
la source
7

Voici un moyen très simple de le faire: https://github.com/JagCesar/iOS-blur

Copiez simplement la couche de UIToolbar et vous avez terminé, AMBlurView le fait pour vous. D'accord, ce n'est pas aussi flou que le centre de contrôle, mais c'est assez flou.

N'oubliez pas qu'iOS7 est sous NDA.

Simon
la source
6

Chaque réponse utilise ici vImageBoxConvolve_ARGB8888 cette fonction est vraiment, vraiment lente, c'est bien, si les performances ne sont pas une exigence de haute priorité, mais si vous l'utilisez pour la transition entre deux contrôleurs de vue (par exemple) cette approche signifie des temps supérieurs à 1 seconde ou peut-être plus, c'est très mauvais pour l'expérience utilisateur de votre application.

Si vous préférez laisser tout ce traitement d'image au GPU (et vous devriez), vous pouvez obtenir un bien meilleur effet et également des temps impressionnants en arrondissant 50 ms (en supposant que vous avez un temps de 1 seconde dans la première approche), alors, faisons-le .

Téléchargez d'abord le GPUImage Framework (licence BSD) ici .

Ensuite, ajoutez les classes suivantes (.m et .h) à partir de GPUImage (je ne suis pas sûr que ce soit le minimum nécessaire pour l'effet de flou uniquement)

  • 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

Ensuite, créez une catégorie sur UIImage, qui ajoutera un effet de flou à un UIImage existant:

#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

Enfin, ajoutez les cadres suivants à votre projet:

AVFoundation CoreMedia CoreVideo OpenGLES

Oui, je me suis amusé avec cette approche beaucoup plus rapide;)

D33pN16h7
la source
4

Vous pouvez essayer d'utiliser ma vue personnalisée, qui a la capacité de rendre l'arrière-plan flou. Il le fait en simulant un instantané de l'arrière-plan et en le floutant, tout comme celui du code WWDC d'Apple. C'est très simple à utiliser.

J'ai également fait quelques améliorations pour simuler le flou dynamique sans perdre les performances. L'arrière-plan de ma vue est un scrollView qui défile avec la vue, fournissant ainsi l'effet de flou pour le reste de la vue d'ensemble.

Voir l'exemple et le code sur mon GitHub

Octet
la source