Crear una vista de superposición borrosa

Respuestas:

552

Puedes usar UIVisualEffectViewpara lograr este efecto. Esta es una API nativa que se ha ajustado para el rendimiento y la excelente duración de la batería, además de que es fácil de implementar.

Rápido:

//only apply the blur if the user hasn't disabled transparency effects
if !UIAccessibility.isReduceTransparencyEnabled {
    view.backgroundColor = .clear

    let blurEffect = UIBlurEffect(style: .dark)
    let blurEffectView = UIVisualEffectView(effect: blurEffect)
    //always fill the view
    blurEffectView.frame = self.view.bounds
    blurEffectView.autoresizingMask = [.flexibleWidth, .flexibleHeight]

    view.addSubview(blurEffectView) //if you have more UIViews, use an insertSubview API to place it where needed
} else {
    view.backgroundColor = .black
}

C objetivo:

//only apply the blur if the user hasn't disabled transparency effects
if (!UIAccessibilityIsReduceTransparencyEnabled()) {
    self.view.backgroundColor = [UIColor clearColor];

    UIBlurEffect *blurEffect = [UIBlurEffect effectWithStyle:UIBlurEffectStyleDark];
    UIVisualEffectView *blurEffectView = [[UIVisualEffectView alloc] initWithEffect:blurEffect];
    //always fill the view
    blurEffectView.frame = self.view.bounds;
    blurEffectView.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight;

    [self.view addSubview:blurEffectView]; //if you have more UIViews, use an insertSubview API to place it where needed
} else {
    self.view.backgroundColor = [UIColor blackColor];
}

Si presenta este controlador de vista de manera modal para desenfocar el contenido subyacente, deberá establecer el estilo de presentación modal en Contexto sobre actual y establecer el color de fondo para borrar para garantizar que el controlador de vista subyacente permanecerá visible una vez que se presente de manera sobresaliente.

Jordan H
fuente
77
Como aclaración del insertSubView:belowSubView:comentario en este código, he usado lo siguiente para establecer el desenfoque como fondo de la vista:view.insertSubview(blurEffectView, atIndex: 0)
Michael Voccola
2
Con referencia a la respuesta anterior, ¿es necesario marcar "if (! UIAccessibilityIsReduceTransparencyEnabled ())" o ¿Podemos omitir eso?
GKK
3
Si está presentando su controlador de vista, asegúrese de cambiar modalPresentationStyle = .overCurrentContext junto con la configuración del color de fondo como claro
Shardul
3
Funciona impresionante !!! Necesita un solo cambio: [self.view insertSubview: blurEffectView atIndex: 1];
Abhishek Thapliyal
2
En iOS 11, encuentro que no es necesario verificarlo manualmente UIAccessibilityIsReduceTransparencyEnabled().
Nate Whittaker
284

Imagen central

Dado que esa imagen en la captura de pantalla es estática, puede usarla CIGaussianBlurdesde Core Image (requiere iOS 6). Aquí hay una muestra: https://github.com/evanwdavis/Fun-with-Masks/blob/master/Fun%20with%20Masks/EWDBlurExampleVC.m

Eso sí, esto es más lento que las otras opciones en esta página.

#import <QuartzCore/QuartzCore.h>

- (UIImage*) blur:(UIImage*)theImage
{   
    // ***********If you need re-orienting (e.g. trying to blur a photo taken from the device camera front facing camera in portrait mode)
    // theImage = [self reOrientIfNeeded:theImage];

    // create our blurred image
    CIContext *context = [CIContext contextWithOptions:nil];
    CIImage *inputImage = [CIImage imageWithCGImage:theImage.CGImage];

    // setting up Gaussian Blur (we could use one of many filters offered by Core Image)
    CIFilter *filter = [CIFilter filterWithName:@"CIGaussianBlur"];
    [filter setValue:inputImage forKey:kCIInputImageKey];
    [filter setValue:[NSNumber numberWithFloat:15.0f] forKey:@"inputRadius"];
    CIImage *result = [filter valueForKey:kCIOutputImageKey];

    // CIGaussianBlur has a tendency to shrink the image a little, 
    // this ensures it matches up exactly to the bounds of our original image
    CGImageRef cgImage = [context createCGImage:result fromRect:[inputImage extent]];

    UIImage *returnImage = [UIImage imageWithCGImage:cgImage];//create a UIImage for this function to "return" so that ARC can manage the memory of the blur... ARC can't manage CGImageRefs so we need to release it before this function "returns" and ends.
    CGImageRelease(cgImage);//release CGImageRef because ARC doesn't manage this on its own.

    return returnImage;

    // *************** if you need scaling
    // return [[self class] scaleIfNeeded:cgImage];
}

+(UIImage*) scaleIfNeeded:(CGImageRef)cgimg {
    bool isRetina = [[[UIDevice currentDevice] systemVersion] intValue] >= 4 && [[UIScreen mainScreen] scale] == 2.0;
    if (isRetina) {
        return [UIImage imageWithCGImage:cgimg scale:2.0 orientation:UIImageOrientationUp];
    } else {
        return [UIImage imageWithCGImage:cgimg];
    }
}

- (UIImage*) reOrientIfNeeded:(UIImage*)theImage{

    if (theImage.imageOrientation != UIImageOrientationUp) {

        CGAffineTransform reOrient = CGAffineTransformIdentity;
        switch (theImage.imageOrientation) {
            case UIImageOrientationDown:
            case UIImageOrientationDownMirrored:
                reOrient = CGAffineTransformTranslate(reOrient, theImage.size.width, theImage.size.height);
                reOrient = CGAffineTransformRotate(reOrient, M_PI);
                break;
            case UIImageOrientationLeft:
            case UIImageOrientationLeftMirrored:
                reOrient = CGAffineTransformTranslate(reOrient, theImage.size.width, 0);
                reOrient = CGAffineTransformRotate(reOrient, M_PI_2);
                break;
            case UIImageOrientationRight:
            case UIImageOrientationRightMirrored:
                reOrient = CGAffineTransformTranslate(reOrient, 0, theImage.size.height);
                reOrient = CGAffineTransformRotate(reOrient, -M_PI_2);
                break;
            case UIImageOrientationUp:
            case UIImageOrientationUpMirrored:
                break;
        }

        switch (theImage.imageOrientation) {
            case UIImageOrientationUpMirrored:
            case UIImageOrientationDownMirrored:
                reOrient = CGAffineTransformTranslate(reOrient, theImage.size.width, 0);
                reOrient = CGAffineTransformScale(reOrient, -1, 1);
                break;
            case UIImageOrientationLeftMirrored:
            case UIImageOrientationRightMirrored:
                reOrient = CGAffineTransformTranslate(reOrient, theImage.size.height, 0);
                reOrient = CGAffineTransformScale(reOrient, -1, 1);
                break;
            case UIImageOrientationUp:
            case UIImageOrientationDown:
            case UIImageOrientationLeft:
            case UIImageOrientationRight:
                break;
        }

        CGContextRef myContext = CGBitmapContextCreate(NULL, theImage.size.width, theImage.size.height, CGImageGetBitsPerComponent(theImage.CGImage), 0, CGImageGetColorSpace(theImage.CGImage), CGImageGetBitmapInfo(theImage.CGImage));

        CGContextConcatCTM(myContext, reOrient);

        switch (theImage.imageOrientation) {
            case UIImageOrientationLeft:
            case UIImageOrientationLeftMirrored:
            case UIImageOrientationRight:
            case UIImageOrientationRightMirrored:
                CGContextDrawImage(myContext, CGRectMake(0,0,theImage.size.height,theImage.size.width), theImage.CGImage);
                break;

            default:
                CGContextDrawImage(myContext, CGRectMake(0,0,theImage.size.width,theImage.size.height), theImage.CGImage);
                break;
        }

        CGImageRef CGImg = CGBitmapContextCreateImage(myContext);
        theImage = [UIImage imageWithCGImage:CGImg];

        CGImageRelease(CGImg);
        CGContextRelease(myContext);
    }

    return theImage;
}

Desenfoque de pila (Box + Gaussian)

  • StackBlur Esto implementa una mezcla de cuadro y desenfoque gaussiano. 7 veces más rápido que el gaussiano no acelerado, pero no tan feo como el cuadro borroso. Vea una demostración aquí (versión del complemento de Java) o aquí (versión de JavaScript). Este algoritmo se usa en KDE y Camera + y otros. No usa Accelerate Framework pero es rápido.

Acelerar el marco

  • En la sesión "Implementación de la interfaz de usuario atractiva en iOS" de WWDC 2013, Apple explica cómo crear un fondo borroso (a las 14:30) y menciona un método applyLightEffectimplementado en el código de muestra usando Accelerate.framework.

  • GPUImage usa sombreadores OpenGL para crear desenfoques dinámicos. Tiene varios tipos de desenfoque: GPUImageBoxBlurFilter, GPUImageFastBlurFilter, GaussianSelectiveBlur, GPUImageGaussianBlurFilter. Incluso hay un GPUImageiOSBlurFilter que "debería replicar completamente el efecto de desenfoque proporcionado por el panel de control de iOS 7" ( tweet , artículo ). El artículo es detallado e informativo.

    - (UIImage *) blurryGPUImage: (UIImage *) imagen con BlurLevel: (NSInteger) blur {
        GPUImageFastBlurFilter * blurFilter = [GPUImageFastBlurFilter nuevo];
        blurFilter.blurSize = blur;
        UIImage * result = [blurFilter imageByFilteringImage: image];
        resultado de retorno;
    }

Otras cosas

Andy Matuschak dijo en Twitter: "ya sabes, muchos de los lugares donde parece que lo estamos haciendo en tiempo real, es estático con trucos ingeniosos".

En doubleencore.com dicen "hemos descubierto que un radio de desenfoque de 10 puntos más un aumento de 10 puntos en la saturación mejor imita el efecto de desenfoque de iOS 7 en la mayoría de las circunstancias".

Un vistazo a los encabezados privados de SBFProceduralWallpaperView de Apple .

Finalmente, esto no es un desenfoque real, pero recuerde que puede configurar rasterizationScale para obtener una imagen pixelada: http://www.dimzzy.com/blog/2010/11/blur-effect-for-uiview/

Jano
fuente
¡Gracias por responder! Un problema está resuelto. Pero tenemos un problema más. ¿Cómo obtener una imagen de portada en iOS 7. Si es posible?
kondratyevdev
Si te refieres a cómo obtener la imagen de fondo de pantalla de tu teléfono, no tengo idea en este momento. No vi esa funcionalidad en las diferencias de API . Tal vez usa una API privada.
Jano
Una cosa que he notado (y podría estar totalmente equivocado) es que el desenfoque de Apple parece agregar también una pequeña saturación de color. Entonces, no creo que sea un simple desenfoque gaussiano.
xtravar
Recuerde el factor de escala cuando devuelva el UIImagedispositivo
Stephen Darlington
¿Sabe si dicho efecto podría aplicarse a un UITableViewCell sin degradar el rendimiento?
Leonardo
15

Decidí publicar una versión escrita de Objective-C de la respuesta aceptada solo para proporcionar más opciones en esta pregunta.

- (UIView *)applyBlurToView:(UIView *)view withEffectStyle:(UIBlurEffectStyle)style andConstraints:(BOOL)addConstraints
{
  //only apply the blur if the user hasn't disabled transparency effects
  if(!UIAccessibilityIsReduceTransparencyEnabled())
  {
    UIBlurEffect *blurEffect = [UIBlurEffect effectWithStyle:style];
    UIVisualEffectView *blurEffectView = [[UIVisualEffectView alloc] initWithEffect:blurEffect];
    blurEffectView.frame = view.bounds;

    [view addSubview:blurEffectView];

    if(addConstraints)
    {
      //add auto layout constraints so that the blur fills the screen upon rotating device
      [blurEffectView setTranslatesAutoresizingMaskIntoConstraints:NO];

      [view addConstraint:[NSLayoutConstraint constraintWithItem:blurEffectView
                                                       attribute:NSLayoutAttributeTop
                                                       relatedBy:NSLayoutRelationEqual
                                                          toItem:view
                                                       attribute:NSLayoutAttributeTop
                                                      multiplier:1
                                                        constant:0]];

      [view addConstraint:[NSLayoutConstraint constraintWithItem:blurEffectView
                                                       attribute:NSLayoutAttributeBottom
                                                       relatedBy:NSLayoutRelationEqual
                                                          toItem:view
                                                       attribute:NSLayoutAttributeBottom
                                                      multiplier:1
                                                        constant:0]];

      [view addConstraint:[NSLayoutConstraint constraintWithItem:blurEffectView
                                                       attribute:NSLayoutAttributeLeading
                                                       relatedBy:NSLayoutRelationEqual
                                                          toItem:view
                                                       attribute:NSLayoutAttributeLeading
                                                      multiplier:1
                                                        constant:0]];

      [view addConstraint:[NSLayoutConstraint constraintWithItem:blurEffectView
                                                       attribute:NSLayoutAttributeTrailing
                                                       relatedBy:NSLayoutRelationEqual
                                                          toItem:view
                                                       attribute:NSLayoutAttributeTrailing
                                                      multiplier:1
                                                        constant:0]];
    }
  }
  else
  {
    view.backgroundColor = [[UIColor blackColor] colorWithAlphaComponent:0.7];
  }

  return view;
}

Las restricciones podrían eliminarse si lo desea en caso de que solo admita el modo vertical o simplemente agregue una bandera a esta función para usarlas o no.

valbu17
fuente
1
para gente nueva (yo), una forma de llamar al método anterior es: [self applyBlurToView: self.view withEffectStyle: UIBlurEffectStyleDark andConstraints: YES]; (gracias NorthBlast)
tmr
14

No creo que se me permita publicar el código, pero la publicación anterior que menciona el código de muestra WWDC es correcta. Aquí está el enlace: https://developer.apple.com/downloads/index.action?name=WWDC%202013

El archivo que está buscando es la categoría en UIImage, y el método es applyLightEffect.

Como señalé anteriormente en un comentario, el Apple Blur tiene saturación y otras cosas además del desenfoque. Un simple desenfoque no servirá ... si está buscando emular su estilo.

xtravar
fuente
8
Ese enlace está roto. Aquí está el enlace correcto: developer.apple.com/downloads/index.action?name=WWDC%202013
olivaresF
Tenga en cuenta que este código de ejemplo requiere XCode 5.0 y iOS SDK 7.0 (que aún no se han lanzado públicamente)
Mike Gledhill
Gracias por el enlace fijo, sin embargo, hay algunos códigos de muestra, ¿cuál contiene la categoría UIImage relevante?
Leonardo
1
@Leonardo iOS_RunningWithASnap.zip
John Starr Dewar
1
... o iOS_UIImageEffects.zip es más específicamente solo esto.
John Starr Dewar
9

Creo que la solución más fácil para esto es anular UIToolbar, que borra todo lo que hay detrás en iOS 7. Es bastante astuto, pero es muy sencillo de implementar y rápido.

Puedes hacerlo con cualquier vista, solo conviértela en una subclase de UIToolbar lugar de UIView. Incluso puedes hacerlo con UIViewControllerla viewpropiedad de un, por ejemplo ...

1) cree una nueva clase que sea una "Subclase de" UIViewControllery marque la casilla "Con XIB para la interfaz de usuario".

2) Seleccione la Vista y vaya al inspector de identidad en el panel de la derecha (alt-command-3). Cambia la "Clase" a UIToolbar. Ahora vaya al inspector de atributos (alt-command-4) y cambie el color de "Fondo" a "Color claro".

3) Agregue una subvista a la vista principal y conéctela a un IBOutlet en su interfaz. Llamarlo backgroundColorView. Se verá más o menos así, como una categoría privada en el .marchivo de implementación ( ).

@interface BlurExampleViewController ()
@property (weak, nonatomic) IBOutlet UIView *backgroundColorView;
@end

4) Vaya al .marchivo de implementación del controlador de vista ( ) y cambie el -viewDidLoadmétodo, para que tenga el siguiente aspecto:

- (void)viewDidLoad
{
    [super viewDidLoad];
    self.view.barStyle = UIBarStyleBlack; // this will give a black blur as in the original post
    self.backgroundColorView.opaque = NO;
    self.backgroundColorView.alpha = 0.5;
    self.backgroundColorView.backgroundColor = [UIColor colorWithWhite:0.3 alpha:1];
}

Esto le dará una vista en gris oscuro, que desdibuja todo lo que hay detrás. Sin negocios divertidos, sin desenfoque lento de la imagen central, utilizando todo lo que está a su alcance proporcionado por el OS / SDK.

Puede agregar la vista de este controlador de vista a otra vista, de la siguiente manera:

[self addChildViewController:self.blurViewController];
[self.view addSubview:self.blurViewController.view];
[self.blurViewController didMoveToParentViewController:self];

// animate the self.blurViewController into view

¡Avíseme si algo no está claro, estaré encantado de ayudarlo!


Editar

UIToolbar se ha cambiado en 7.0.3 para dar un efecto posiblemente no deseado cuando se usa un desenfoque de color.

Solíamos poder configurar el color usando barTintColor, pero si lo hacía antes, necesitará configurar el componente alfa en menos de 1. De lo contrario, su UIToolbar será de color completamente opaco, sin desenfoque.

Esto se puede lograr de la siguiente manera: (teniendo en cuenta que selfes una subclase de UIToolbar)

UIColor *color = [UIColor blueColor]; // for example
self.barTintColor = [color colorWithAlphaComponent:0.5];

Esto le dará un tono azulado a la vista borrosa.

Sam
fuente
1
No es mal hombre. Utilicé estas tres líneas en mi punto de vista: self.backgroundColorView.opaque = NO; self.backgroundColorView.alpha = 0.5; self.backgroundColorView.backgroundColor = [UIColor colorWithWhite:0.3 alpha:1];pero el fondo no está borroso, solo tiene un bonito efecto de sobre. gracias de todos modos!
IgniteCoders
1
No veo ningún desenfoque en absoluto usando esta técnica. Simplemente crea una superposición de color.
MusiGenesis
asegúrese de que la superposición alfa de color sea menor que 1. Puede usar una UIToolbar sin el controlador de vista, lo que puede ser más simple según lo que necesite.
Sam
hombre truco aseado. Convertí mi vista a la clase UIToolbar en el guión gráfico, luego cambié el fondo de la vista a un color claro. Le dio un fondo blanco borroso. Si haces alfa menos de 1, el efecto borroso desaparecerá.
Badr
9

Aquí hay una implementación rápida en Swift usando CIGaussianBlur:

func blur(image image: UIImage) -> UIImage {
    let radius: CGFloat = 20;
    let context = CIContext(options: nil);
    let inputImage = CIImage(CGImage: image.CGImage!);
    let filter = CIFilter(name: "CIGaussianBlur");
    filter?.setValue(inputImage, forKey: kCIInputImageKey);
    filter?.setValue("\(radius)", forKey:kCIInputRadiusKey);
    let result = filter?.valueForKey(kCIOutputImageKey) as! CIImage;
    let rect = CGRectMake(radius * 2, radius * 2, image.size.width - radius * 4, image.size.height - radius * 4)
    let cgImage = context.createCGImage(result, fromRect: rect);
    let returnImage = UIImage(CGImage: cgImage);

    return returnImage;
}
kev
fuente
7

Escala de desenfoque personalizada

Puede probar UIVisualEffectView con una configuración personalizada como:

class BlurViewController: UIViewController {
    private let blurEffect = (NSClassFromString("_UICustomBlurEffect") as! UIBlurEffect.Type).init()

    override func viewDidLoad() {
        super.viewDidLoad()
        let blurView = UIVisualEffectView(frame: UIScreen.main.bounds)
        blurEffect.setValue(1, forKeyPath: "blurRadius")
        blurView.effect = blurEffect
        view.addSubview(blurView)
    }   
}

Salida: para blurEffect.setValue(1...y blurEffect.setValue(2.. ingrese la descripción de la imagen aquí ingrese la descripción de la imagen aquí

Jack
fuente
3
Dejará de funcionar si en la próxima versión del nombre de iOS de este parámetro se cambia.
Ariel Bogdziewicz
@ArielBogdziewicz actualmente está funcionando. actualizaré si hay alguna variación de API en wwdc.
Jack
Ummm ... no, nunca quieres acceder a API privadas. Son privados por una razón. Cambiarán, se romperán y / o Apple rechazará su aplicación. Usa otro método, hay mucho. Felicitaciones por encontrar el truco, pero no recomendado.
n13
@ Jack ¡Muchas gracias por esta respuesta! Es la única solución que encontré para mi problema: difuminar una vista de acuerdo con la posición de otra vista. Sin embargo, todavía tengo otra pregunta. ¿Hay alguna manera de agregar vitalidad a mi UIBlurEffect? ¿Si es así, cómo? ¿Necesito crear otra vista para esto encima de mi blurView? Lo intenté pero siempre fallaba cuando lo usaba. (NSClassFromString("_UICustomVibrancyEffect") as! UIVibrancyEffect.Type).init()¡Realmente agradecería algo de ayuda!
Moritz
@ Moritz no lo ha intentado. Pero debería funcionar. Puedes probar y comprobar.
Jack
7

Aquí hay una manera fácil de agregar desenfoque personalizado sin regatear con API privadas usando UIViewPropertyAnimator :

Primero, declare la propiedad de clase:

var blurAnimator: UIViewPropertyAnimator!

Luego configure su vista borrosa en viewDidLoad():

let blurEffectView = UIVisualEffectView()
blurEffectView.backgroundColor = .clear
blurEffectView.frame = view.bounds
blurEffectView.autoresizingMask = [.flexibleWidth, .flexibleHeight]
view.addSubview(blurEffectView)

blurAnimator = UIViewPropertyAnimator(duration: 1, curve: .linear) { [blurEffectView] in
    blurEffectView.effect = UIBlurEffect(style: .light)
}

blurAnimator.fractionComplete = 0.15 // set the blur intensity.    

Nota: Esta solución no es adecuada para UICollectionView/ UITableViewceldas

Adam Bardon
fuente
1
Esta es la única solución que encontré si desea controlar la transparencia de UIVisualEffectView.
Denis Kutlubaev
6

ingrese la descripción de la imagen aquí

Desde Xcode puedes hacerlo fácilmente. Siga los pasos de xcode. Grabe la vista de efectos visuales en su vista uiview o imagen.

Happy Coding :)

Mehedi Hasan
fuente
5

La respuesta aceptada es correcta, pero falta un paso importante aquí, en caso de que esta vista, para la que desea un fondo borroso, se presente utilizando

[self presentViewController:vc animated:YES completion:nil]

De forma predeterminada, esto negará el desenfoque ya que UIKit elimina la vista del presentador, que en realidad está borrando. Para evitar esa eliminación, agregue esta línea antes de la anterior

vc.modalPresentationStyle = UIModalPresentationOverFullScreen;

O usa otros Overestilos.

Aleksandar Vacić
fuente
3

C OBJETIVO

UIVisualEffect *blurEffect;
blurEffect = [UIBlurEffect effectWithStyle:UIBlurEffectStyleDark];
UIVisualEffectView *visualEffectView;
visualEffectView = [[UIVisualEffectView alloc] initWithEffect:blurEffect];
visualEffectView.frame = self.accessImageView.bounds;
[self.accessImageView addSubview:visualEffectView];

SWIFT 3.0

let blurEffect = UIBlurEffect(style: UIBlurEffectStyle.dark)
let blurEffectView = UIVisualEffectView(effect: blurEffect)
blurEffectView.frame = view.bounds
blurEffectView.autoresizingMask = [.flexibleWidth, .flexibleHeight]
view.addSubview(blurEffectView)

de: https://stackoverflow.com/a/24083728/4020910

BennyTheNerd
fuente
2

Usando UIImageEffects

Para las personas que desean un mayor control, puede utilizar el UIImageEffectscódigo de muestra de Apple .

Puede copiar el código UIImageEffectsde la Biblioteca de desarrolladores de Apple: Desenfocar y teñir una imagen

Y aquí está cómo aplicarlo:

#import "UIImageEffects.h"
...

self.originalImageView.image = [UIImageEffects imageByApplyingLightEffectToImage:[UIImage imageNamed:@"yourImage.png"]];
Zakaria Braksa
fuente
¿Cómo uso esto en
Swift
2
func blurBackgroundUsingImage(image: UIImage)
{
    var frame                   = CGRectMake(0, 0, self.view.frame.width, self.view.frame.height)
    var imageView               = UIImageView(frame: frame)
    imageView.image             = image
    imageView.contentMode       = .ScaleAspectFill
    var blurEffect              = UIBlurEffect(style: .Light)
    var blurEffectView          = UIVisualEffectView(effect: blurEffect)
    blurEffectView.frame        = frame
    var transparentWhiteView    = UIView(frame: frame)
    transparentWhiteView.backgroundColor = UIColor(white: 1.0, alpha: 0.30)
    var viewsArray              = [imageView, blurEffectView, transparentWhiteView]

    for index in 0..<viewsArray.count {
        if let oldView = self.view.viewWithTag(index + 1) {
            var oldView         = self.view.viewWithTag(index + 1)
            // Must explicitly unwrap oldView to access its removeFromSuperview() method as of Xcode 6 Beta 5
            oldView!.removeFromSuperview()
        }
        var viewToInsert        = viewsArray[index]
        self.view.insertSubview(viewToInsert, atIndex: index + 1)
        viewToInsert.tag        = index + 1
    }
}
Durul Dalkanat
fuente
1

Encontré esto por accidente, me da excelentes resultados (casi duplicados con los de Apple) y usa el marco de aceleración. - http://pastebin.com/6cs6hsyQ * No escrito por mí

Jake
fuente
8
En realidad, es el código de Apple de WWDC 2013 con derechos de autor incorrectos.
Shmidt
¿No están protegidos por derechos de autor los códigos de WWDC y solo se permite el acceso a los miembros con suscripciones pagas?
SAFAD
1
Posiblemente, pero el código anterior lo encontré usando Google. No he cambiado los derechos de autor y asumí (y aún asumo) que tiene el reclamo de derechos de autor correcto. Si Apple no está de acuerdo, deberían esforzarse por eliminarlo. No veo la relevancia.
Jake
1

Esta respuesta se basa en la excelente respuesta anterior de Mitja Semolic . Lo convertí a Swift 3, agregué una explicación de lo que está sucediendo en los comentarios, lo convertí en una extensión de UIViewController para que cualquier VC pueda llamarlo a voluntad, agregué una vista borrosa para mostrar una aplicación selectiva y agregué un bloque de finalización para que el controlador de vista de llamada puede hacer lo que quiera al finalizar el desenfoque.

    import UIKit
//This extension implements a blur to the entire screen, puts up a HUD and then waits and dismisses the view.
    extension UIViewController {
        func blurAndShowHUD(duration: Double, message: String, completion: @escaping () -> Void) { //with completion block
            //1. Create the blur effect & the view it will occupy
            let blurEffect = UIBlurEffect(style: UIBlurEffectStyle.light)
            let blurEffectView = UIVisualEffectView()//(effect: blurEffect)
            blurEffectView.frame = self.view.bounds
            blurEffectView.autoresizingMask = [.flexibleWidth, .flexibleHeight]

        //2. Add the effect view to the main view
            self.view.addSubview(blurEffectView)
        //3. Create the hud and add it to the main view
        let hud = HudView.getHUD(view: self.view, withMessage: message)
        self.view.addSubview(hud)
        //4. Begin applying the blur effect to the effect view
        UIView.animate(withDuration: 0.01, animations: {
            blurEffectView.effect = blurEffect
        })
        //5. Halt the blur effects application to achieve the desired blur radius
        self.view.pauseAnimationsInThisView(delay: 0.004)
        //6. Remove the view (& the HUD) after the completion of the duration
        DispatchQueue.main.asyncAfter(deadline: .now() + duration) {
            blurEffectView.removeFromSuperview()
            hud.removeFromSuperview()
            self.view.resumeAnimationsInThisView()
            completion()
        }
    }
}

extension UIView {
    public func pauseAnimationsInThisView(delay: Double) {
        let time = delay + CFAbsoluteTimeGetCurrent()
        let timer = CFRunLoopTimerCreateWithHandler(kCFAllocatorDefault, time, 0, 0, 0, { timer in
            let layer = self.layer
            let pausedTime = layer.convertTime(CACurrentMediaTime(), from: nil)
            layer.speed = 0.0
            layer.timeOffset = pausedTime
        })
        CFRunLoopAddTimer(CFRunLoopGetCurrent(), timer, CFRunLoopMode.commonModes)
    }
    public func resumeAnimationsInThisView() {
        let pausedTime  = layer.timeOffset

        layer.speed = 1.0
        layer.timeOffset = 0.0
        layer.beginTime = layer.convertTime(CACurrentMediaTime(), from: nil) - pausedTime
    }
}

He confirmado que funciona con iOS 10.3.1 y iOS 11

James Jordan Taylor
fuente
1

Un suplemento importante a la respuesta de @ Joey

Esto se aplica a una situación en la que desea presentar un fondo borroso UIViewControllercon UINavigationController.

// suppose you've done blur effect with your presented view controller
UINavigationController *nav = [[UINavigationController alloc] initWithRootViewController];

// this is very important, if you don't do this, the blur effect will darken after view did appeared
// the reason is that you actually present navigation controller, not presented controller
// please note it's "OverFullScreen", not "OverCurrentContext"
nav.modalPresentationStyle = UIModalPresentationOverFullScreen;

UIViewController *presentedViewController = [[UIViewController alloc] init]; 
// the presented view controller's modalPresentationStyle is "OverCurrentContext"
presentedViewController.modalPresentationStyle = UIModalPresentationOverCurrentContext;

[presentingViewController presentViewController:nav animated:YES completion:nil];

¡Disfrutar!

steveluoxin
fuente
1

Versión Swift 3 de la respuesta de Kev para devolver una imagen borrosa -

func blurBgImage(image: UIImage) -> UIImage? {
        let radius: CGFloat = 20;
        let context = CIContext(options: nil);
        let inputImage = CIImage(cgImage: image.cgImage!);
        let filter = CIFilter(name: "CIGaussianBlur");
        filter?.setValue(inputImage, forKey: kCIInputImageKey);
        filter?.setValue("\(radius)", forKey:kCIInputRadiusKey);

        if let result = filter?.value(forKey: kCIOutputImageKey) as? CIImage{

            let rect = CGRect(origin: CGPoint(x: radius * 2,y :radius * 2), size: CGSize(width: image.size.width - radius * 4, height: image.size.height - radius * 4))

            if let cgImage = context.createCGImage(result, from: rect){
                return UIImage(cgImage: cgImage);
                }
        }
        return nil;
    }
Pramod
fuente
1

Código 2019

Aquí hay un ejemplo más completo usando la sorprendente técnica @AdamBardon.

@IBDesignable class ButtonOrSomethingWithBlur: UIButton {

    var ba: UIViewPropertyAnimator?
    private lazy var blurry: BlurryBall = { return BlurryBall() }()

    override func didMoveToSuperview() {
        super.didMoveToSuperview()

        // Setup the blurry ball.  BE SURE TO TEARDOWN.
        // Use superb trick to access the internal guassian level of Apple's
        // standard gpu blurrer per stackoverflow.com/a/55378168/294884

        superview?.insertSubview(blurry, belowSubview: self)
        ba = UIViewPropertyAnimator(duration:1, curve:.linear) {[weak self] in
            // note, those duration/curve values are simply unusued
            self?.blurry.effect = UIBlurEffect(style: .extraLight)
        }
        ba?.fractionComplete = live.largeplaybutton_blurfactor
    }

    override func willMove(toSuperview newSuperview: UIView?) {

        // Teardown for the blurry ball - critical

        if newSuperview == nil { print("safe teardown")
            ba?.stopAnimation(true)
            ba?.finishAnimation(at: .current)
        }
    }

    override func layoutSubviews() { super.layoutSubviews()
        blurry.frame = bounds, your drawing frame or whatever
    }

{Aparte: como cuestión general de ingeniería de iOS, didMoveToWindowpuede ser más adecuado para usted quedidMoveToSuperview . En segundo lugar, puede utilizar alguna otra forma de desmontaje, pero el desmontaje son las dos líneas de código que se muestran allí.}

BlurryBalles solo un UIVisualEffectView. Observe los inits para una vista de efectos visuales. Si necesita esquinas redondeadas o lo que sea, hágalo en esta clase.

class BlurryBall: UIVisualEffectView {

    override init(effect: UIVisualEffect?) { super.init(effect: effect)
        commonInit() }

    required init?(coder aDecoder: NSCoder) { super.init(coder: aDecoder)
        commonInit() }

    private func commonInit() {
        clipsToBounds = true
        backgroundColor = .clear
    }

    override func layoutSubviews() {
        super.layoutSubviews()
        layer.cornerRadius = bounds.width / 2
    }
}
Fattie
fuente
0

Apple ha proporcionado una extensión para la clase UIImage llamada UIImage + ImageEffects.h. En esta clase, tiene los métodos deseados para difuminar su vista

Saludar
fuente
1
¿Puedes compartir más información sobre estos métodos?
Mike Laren
0

Aquí está el código Swift 2.0 para la solución que se ha proporcionado en la respuesta aceptada :

    //only apply the blur if the user hasn't disabled transparency effects
    if !UIAccessibilityIsReduceTransparencyEnabled() {
        self.view.backgroundColor = UIColor.clearColor()

        let blurEffect = UIBlurEffect(style: UIBlurEffectStyle.Dark)
        let blurEffectView = UIVisualEffectView(effect: blurEffect)
        //always fill the view
        blurEffectView.frame = self.view.bounds
        blurEffectView.autoresizingMask = [.FlexibleWidth, .FlexibleHeight]

        self.view.addSubview(blurEffectView) //if you have more UIViews, use an insertSubview API to place it where needed
    } else {
        self.view.backgroundColor = UIColor.blackColor()
    }
RaptoX
fuente
0

Si agrega una vista borrosa oscura para tableView, esto lo hará maravillosamente:

tableView.backgroundColor = .clear
let blurEffect = UIBlurEffect(style: .dark)
let blurEffectView = UIVisualEffectView(effect: blurEffect)
blurEffectView.frame = tableView.bounds
blurEffectView.autoresizingMask = [.flexibleHeight, .flexibleWidth]


// Assigning blurEffectView to backgroundView instead of addSubview to tableView makes tableView cell not blocked by blurEffectView 
tableView.backgroundView = blurEffectView
Chao
fuente
0

Puede hacer su desenfoque de fondo directamente con "Vista de efecto visual con desenfoque" y "Vista de efecto visual con desenfoque y vitalidad".

Todo lo que tienes que hacer para hacer Blur Background en la aplicación iOS es ...

  1. Vaya y busque "Vista de efecto visual con desenfoque" en la Biblioteca de objetos

Paso 1 Imagen

  1. Arrastre la "Vista de efecto visual con desenfoque" en su Guión gráfico y configúrela ...

Paso 2 Imagen

  1. Finalmente ... ¡Haces que tu aplicación sea borrosa en el fondo!

Diseño de la aplicación antes de hacer clic en cualquier botón!

Vista de la aplicación después de hacer clic en el botón, lo que hace que todo el fondo de la aplicación se vuelva borroso.

Conoce a patel
fuente
0

En caso de que esto ayude a alguien, aquí hay una extensión rápida que creé basada en la respuesta de Jordan H. Está escrita en Swift 5 y puede usarse desde el Objetivo C.

extension UIView {

    @objc func blurBackground(style: UIBlurEffect.Style, fallbackColor: UIColor) {
        if !UIAccessibility.isReduceTransparencyEnabled {
            self.backgroundColor = .clear

            let blurEffect = UIBlurEffect(style: style)
            let blurEffectView = UIVisualEffectView(effect: blurEffect)
            //always fill the view
            blurEffectView.frame = self.self.bounds
            blurEffectView.autoresizingMask = [.flexibleWidth, .flexibleHeight]

            self.insertSubview(blurEffectView, at: 0)
        } else {
            self.backgroundColor = fallbackColor
        }
    }

}

NOTA: Si desea desenfocar el fondo de un UILabel sin afectar el texto, debe crear un UIView de contenedor, agregar el UILabel al UIView del contenedor como una subvista, establecer el backgroundColor de UILabel en UIColor.clear y luego llamar a blurBackground (style : UIBlurEffect.Style, fallbackColor: UIColor) en el contenedor UIView. Aquí hay un ejemplo rápido de esto escrito en Swift 5:

let frame = CGRect(x: 50, y: 200, width: 200, height: 50)
let containerView = UIView(frame: frame)
let label = UILabel(frame: frame)
label.text = "Some Text"
label.backgroundColor = UIColor.clear
containerView.addSubview(label)
containerView.blurBackground(style: .dark, fallbackColor: UIColor.black)
Tyler Wood
fuente
-1

Swift 4:

Para agregar una superposición o la vista emergente También puede usar la Vista de contenedor con la que obtiene un Controlador de vista gratuito (obtiene la Vista de contenedor de la paleta / biblioteca de objetos habitual)

Pasos:

Tenga una Vista (ViewForContainer en la imagen) que contenga esta Vista de contenedor, para atenuarla cuando se muestre el contenido de la Vista de contenedor. Conecte la salida dentro del primer controlador de vista

Ocultar esta vista cuando se carga el primer VC

Mostrar cuando se hace clic en el botón ingrese la descripción de la imagen aquí

Para atenuar esta vista cuando se muestra el contenido de la vista de contenedor, configure el fondo de las vistas en negro y la opacidad en 30%

He agregado una respuesta a la creación de la vista popview en otra pregunta de Stackoverflow https://stackoverflow.com/a/49729431/5438240

Naishta
fuente
-3

La respuesta simple es Agregar una subvista y cambiar su alfa.

UIView *mainView = [[UIView alloc] initWithFrame:CGRectMake(0, 0, 200, 200)];
UIView *subView = [[UIView alloc] initWithFrame:popupView.frame];
UIColor * backImgColor = [UIColor colorWithPatternImage:[UIImage imageNamed:@"blue_Img.png"]];
subView.backgroundColor = backImgColor;
subView.alpha = 0.5;
[mainView addSubview:subView];
Sohail
fuente