Vista de desenfoque de estilo iOS 7

113

¿Alguien sabe de algún control que replicará las vistas de desenfoque de estilo iOS7?

Supongo que puede haber algún tipo de subclase UIView que replicará el comportamiento.

Estoy hablando de estos tipos de vistas que difuminan el fondo de manera extremadamente gruesa para que tengan efectos de extracción de la vista de fondo.

ingrese la descripción de la imagen aquí

endy
fuente
6
GPUImage podría ayudar.
Maarten
@Anil, entonces la pregunta será cuando se lance el SDK de ios7, ¿cómo puedo hacer esto sin restringir mi aplicación solo a ios7?).
finaliza el
1
Apple ha lanzado una categoría UIImage que hace exactamente esto. Solo intento encontrarlo.
Fogmeister
1
El código está vinculado desde la sesión 201 de WWDC. Es público en github. No puedo encontrarlo en el cajero automático.
Fogmeister

Respuestas:

40

Es posible que pueda modificar algo como RWBlurPopover de Bin Zhang para hacer esto. Ese componente usa mi GPUImage para aplicar un desenfoque gaussiano a los componentes debajo de él, pero también podría usar un CIGaussianBlur para lo mismo. Sin embargo, GPUImage podría ser un poco más rápido .

Sin embargo, ese componente depende de que usted pueda capturar la vista detrás de la que está presentando y puede tener problemas con las vistas que se animan detrás de este contenido. La necesidad de hacer un viaje a través de Core Graphics para rasterizar la vista de fondo ralentizará las cosas, por lo que probablemente no tengamos acceso directo suficiente para poder hacer esto de manera eficiente para superposiciones en vistas animadas.

Como actualización de lo anterior, recientemente modifiqué los desenfoques en GPUImage para admitir radios variables, lo que permite la replicación completa del tamaño del desenfoque en la vista del centro de control de iOS 7. A partir de eso, creé la clase GPUImageiOS7BlurFilter que encapsula el tamaño de desenfoque adecuado y la corrección de color que Apple parece estar usando aquí. Así es como el desenfoque de GPUImage (a la derecha) se compara con el desenfoque incorporado (a la izquierda):

El desenfoque de Apple Desenfoque de GPUImage

Utilizo un aumento / disminución de resolución de 4X para reducir la cantidad de píxeles sobre los que tiene que operar el desenfoque gaussiano, por lo que un iPhone 4S puede desenfocar toda la pantalla en aproximadamente 30 ms con esta operación.

Todavía tiene el desafío de cómo atraer contenido a este desenfoque desde las vistas detrás de este de una manera eficaz.

Brad Larson
fuente
Entonces, ¿cómo crees que Apple lo está logrando? Si abre la aplicación Cámara y abre el Centro de control (la pantalla de configuración de la parte inferior), el desenfoque sigue lo que ve la cámara.
Muñeco de nieve
2
@maq: ayuda tener acceso bajo el capó a todo en el sistema. Lo que puede hacer alguien que desarrolla el sistema operativo es muy diferente de lo que nos permiten hacer las interfaces públicas.
Brad Larson
3
@maq: la cámara se alimenta específicamente, sí. Una forma de hacer esto sería usar GPUImage para extraer los cuadros de la cámara (a través de AV Foundation) y luego tener esa salida tanto en GPUImageView para la salida de la cámara en vivo y luego, en paralelo, alimentar un desenfoque gaussiano (y posiblemente un recorte para que coincida con la posición de la vista borrosa) y esa salida a otra GPUImageView que mostraría el contenido borroso detrás de sus controles. Eso es posible porque tenemos una ruta rápida desde los fotogramas de la cámara a OpenGL ES, pero no tenemos nada similar para los elementos genéricos de la interfaz de usuario.
Brad Larson
1
Estoy tomando una captura de pantalla de un UIView mediante programación y usando GPUImageGaussianBlurFilter para intentar crear un efecto similar, pero el resultado es muy diferente del estilo de Apple. El filtro parece difuminarse en una cuadrícula, con cuadrados visibles en todas partes, donde Apple es solo una hoja lisa.
Muñeco de nieve
1
@maq: asegúrese de que está utilizando el código más reciente del repositorio, porque antes había un error en los radios de desenfoque alto. Dicho esto, el desenfoque solo muestra un área de 9 píxeles de forma predeterminada, por lo que si aumenta el multiplicador para el desenfoque más allá de ese punto, comenzará a ver artefactos al omitir píxeles. Esto se hace por motivos de rendimiento, pero puede modificar los sombreadores de vértices y fragmentos para muestrear una mayor cantidad de píxeles. Eso, o intente aplicar un CIGaussianBlur, que tiene una implementación de desenfoque más generalizada. Uno de estos días, extenderé este desenfoque a radios más grandes.
Brad Larson
28

Estoy usando FXBlurViewque funciona muy bien en iOS5 +

https://github.com/nicklockwood/FXBlurView

CocoaPods:

-> FXBlurView (1.3.1)
   UIView subclass that replicates the iOS 7 realtime background blur effect, but works on iOS 5 and above.
   pod 'FXBlurView', '~> 1.3.1'
   - Homepage: http://github.com/nicklockwood/FXBlurView
   - Source:   https://github.com/nicklockwood/FXBlurView.git
   - Versions: 1.3.1, 1.3, 1.2, 1.1, 1.0 [master repo]

Lo agregué usando:

FXBlurView *blurView = [[FXBlurView alloc] initWithFrame:CGRectMake(50, 50, 150, 150)];
[self.blurView setDynamic:YES];
[self.view addSubview:self.blurView];
Paul Peelen
fuente
2
¿Hay algún truco para usar FXBlurView? Lo he intentado, pero hemos obtenido visualizaciones retrasadas en un iPhone 5. Su proyecto de demostración funciona bien. Bastante extraño.
Cris
Depende de lo que quieras hacer. Cuando coloco FXBlurViewencima de un UIScrollView, también obtuve un resultado lento. Creo que esto tiene que ver con la forma en que se agrega el desenfoque. Apple, si no me equivoco, está accediendo directamente a la GPU cuando usa su propio desenfoque, lo que no podemos hacer como desarrolladores. Por lo tanto, la solución @cprcrack es en realidad la mejor solución aquí.
Paul Peelen
2
¿Cómo ha manejado las rotaciones de dispositivos con FXBlurView? Estoy presentando un diálogo modal en este momento; el cuadro de diálogo en sí gira bien, pero el fondo está aplastado de manera incorrecta (básicamente, necesita actualizarse después de la rotación).
fatuhoku
1
por supuesto, FXBlurView es una buena opción, pero cuando se trata de uso de CPU. de lo que prefiero otro BlurView. Yo uso esto en mi UICollectionVIew y UITableView pero aumenta el uso de mi CPU. en la próxima ejecución comento esas asignaciones y se vuelve normal. Espero que esto ayude a alguien.
Vatsal Shukla
27

ADVERTENCIA: alguien en los comentarios declaró que Apple rechaza las aplicaciones que utilizan esta técnica. Eso NO me pasó a mí, sino solo para su consideración.

Esto puede sorprenderte, pero puedes usar una UIToolbar , que ya incluye ese efecto estándar (solo iOS 7+). En la vista del controlador, viewDidLoad:

self.view.opaque = NO;
self.view.backgroundColor = [UIColor clearColor]; // Be sure in fact that EVERY background in your view's hierarchy is totally or at least partially transparent for a kind effect!

UIToolbar *fakeToolbar = [[UIToolbar alloc] initWithFrame:self.view.bounds];
fakeToolbar.autoresizingMask = self.view.autoresizingMask;
// fakeToolbar.barTintColor = [UIColor white]; // Customize base color to a non-standard one if you wish
[self.view insertSubview:fakeToolbar atIndex:0]; // Place it below everything
cprcrack
fuente
1
Sí, me sorprendió. Verifiqué, esta idea funciona. Hice solo un cambio de línea viewDidLoadasí. - (void) viewDidLoad {[super viewDidLoad]; self.view = [[UIToolbar alloc] initWithFrame: CGRectZero]; } En mi caso, diseño mis vistas mediante programación (estilo antiguo). Voto esta solución porque UIToolbar hereda UIView, por lo que fundamentalmente no veo ningún problema en esta solución. Probaré más a medida que avance con el desarrollo y probaré esta solución.
Ashok
Esta es una gran idea y parece funcionar muy bien. Ojalá tuviera más control, ¡pero esto es tan bueno como parece! Dicho esto, @SudhirJonathan mencionó un enlace arriba donde el autor lleva esto al siguiente nivel: ¡ROBA LA CALAYER de una UIToolBar y la vuelve a utilizar! ¡Brillante!
David H
2
De Verdad? ¿Por qué motivos? No está usando ninguna API privada, y si se rechazaran todas las formas innovadoras de hacer las cosas, muchos efectos no serían posibles ...
TheEye
Trabajé en mi iPhone con iOS 7.1
martes
¿Hay alguna forma de "apagar" la borrosidad?
maxisme
13

Desde iOS8 puedes usar UIBlurEffect .

Hay buenos ejemplos en iOS8Sampler con UIBlurEffect y UIVibrancyEffect .

VivienCormier
fuente
2
Para los perezosos: UIVisualEffect *blurEffect = [UIBlurEffect effectWithStyle:UIBlurEffectStyleDark]; UIVisualEffectView *blurView = [[UIVisualEffectView alloc] initWithEffect:blurEffect];
Ric Santos
13

La mejor forma nueva de obtener una superposición borrosa es usar la nueva función UIVisualEffectView de iOS 8.

UIBlurEffect *effect = [UIBlurEffect effectWithStyle:UIBlurEffectStyleLight];

UIVisualEffectView *bluredView = [[UIVisualEffectView alloc] initWithEffect:effect];

bluredView.frame = self.view.bounds;

[self.view addSubview:bluredView];

UIBlurEffect admite tres tipos de estilo. Oscuro, Claro y Extra claro.

Jeanette Müller
fuente
1

Puede crear una clase con UIToolBar que sea una subclase de UIView y crear una instancia en un controlador de vista separado. Este enfoque demuestra un UIToolBar translúcido (subclasificado por UIView) que proporciona comentarios en vivo (en este caso para una AVCaptureSession).

YourUIView.h

#import <UIKit/UIKit.h>

@interface YourUIView : UIView
@property (nonatomic, strong) UIColor *blurTintColor;
@property (nonatomic, strong) UIToolbar *toolbar;
@end

YourUIView.m

#import "YourUIView.h"

@implementation YourUIView

- (instancetype)init
{
    self = [super init];
    if (self) {
        [self setup];
    }
    return self;
}

- (void)setup {
    // If we don't clip to bounds the toolbar draws a thin shadow on top
    [self setClipsToBounds:YES];

    if (![self toolbar]) {
        [self setToolbar:[[UIToolbar alloc] initWithFrame:[self bounds]]];
        [self.toolbar setTranslatesAutoresizingMaskIntoConstraints:NO];
        [self insertSubview:[self toolbar] atIndex:0];

        [self addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"H:|[_toolbar]|"
                                                                     options:0
                                                                     metrics:0
                                                                       views:NSDictionaryOfVariableBindings(_toolbar)]];
        [self addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"V:|[_toolbar]|"
                                                                     options:0
                                                                     metrics:0
                                                                       views:NSDictionaryOfVariableBindings(_toolbar)]];
    }
}

- (void) setBlurTintColor:(UIColor *)blurTintColor {
    [self.toolbar setBarTintColor:blurTintColor];
}

@end

Una vez que se haya personalizado el UIView anterior, continúe y cree una clase que sea una subclase de un ViewController. A continuación, he creado una clase que utiliza una sesión AVCapture. Debe usar AVCaptureSession para anular la configuración de la cámara integrada de Apple. Por lo tanto, puede superponer el UIToolBar translúcido de la clase YourUIView .

YourViewController.h

#import <UIKit/UIKit.h>

@interface YourViewController : UIViewController
@property (strong, nonatomic) UIView *frameForCapture;
@end

YourViewController.m

#import "YourViewController.h"
#import <AVFoundation/AVFoundation.h>
#import "TestView.h"

@interface YourViewController ()
@property (strong, nonatomic) UIButton *displayToolBar;

@end

@implementation YourViewController


AVCaptureStillImageOutput *stillImageOutput;
AVCaptureSession *session;

- (void) viewWillAppear:(BOOL)animated
{
    session = [[AVCaptureSession alloc] init];
    [session setSessionPreset:AVCaptureSessionPresetPhoto];

    AVCaptureDevice *inputDevice = [AVCaptureDevice defaultDeviceWithMediaType:AVMediaTypeVideo];
    NSError *error;
    AVCaptureDeviceInput *deviceInput = [AVCaptureDeviceInput deviceInputWithDevice:inputDevice error:&error];

    if ([session canAddInput:deviceInput]) {
        [session addInput:deviceInput];
    }

    AVCaptureVideoPreviewLayer *previewLayer = [[AVCaptureVideoPreviewLayer alloc] initWithSession:session];
    [previewLayer setVideoGravity:AVLayerVideoGravityResizeAspectFill];
    CALayer *rootLayer = [[self view] layer];
    [rootLayer setMasksToBounds:YES];
    CGRect frame = [[UIScreen mainScreen] bounds];

    self.frameForCapture.frame = frame;

    [previewLayer setFrame:frame];

    [rootLayer insertSublayer:previewLayer atIndex:0];

    stillImageOutput = [[AVCaptureStillImageOutput alloc] init];
    NSDictionary *outputSettings = [[NSDictionary alloc] initWithObjectsAndKeys:AVVideoCodecJPEG, AVVideoCodecKey, nil];
    [stillImageOutput setOutputSettings:outputSettings];

    [session addOutput:stillImageOutput];

    [session startRunning];

    [self.navigationController setNavigationBarHidden:YES animated:animated];
    [super viewWillAppear:animated];
}


- (void)viewDidLoad
{
    [super viewDidLoad];

    /* Open button */

    UIButton *button = [[UIButton alloc] initWithFrame:CGRectMake(0, 350, self.view.bounds.size.width, 50)];
    [button addTarget:self action:@selector(showYourUIView:) forControlEvents:UIControlEventTouchUpInside];
    [button setTitle:@"Open" forState:UIControlStateNormal];
    [button setTitleColor:[UIColor redColor] forState:UIControlStateNormal];
    button.backgroundColor = [UIColor greenColor];
    [self.view addSubview:button];

    UIButton *anotherButton = [[UIButton alloc] initWithFrame:CGRectMake(0, 50, self.view.bounds.size.width, 50)];
    [anotherButton addTarget:self action:@selector(showYourUIView:) forControlEvents:UIControlEventTouchUpInside];
    [anotherButton setTitle:@"Open" forState:UIControlStateNormal];
    [anotherButton setTitleColor:[UIColor greenColor] forState:UIControlStateNormal];
    anotherButton.backgroundColor = [UIColor redColor];
    [self.view addSubview:anotherButton];

}

- (void) showYourUIView:(id) sender
{
    TestView *blurView = [TestView new];
    [blurView setFrame:self.view.bounds];
    [self.view addSubview:blurView];
}


@end
74U n3U7r1no
fuente
La respuesta parece no tener ninguna relación con la pregunta.
combinatoria
@combinatorial Esta es una de las formas más eficientes de agregar una vista transparente a otro controlador de vista. Incluí el código AVCapture para mostrar que podría usarse para comentarios en vivo en lugar de simplemente agregar una imagen de fondo borrosa, como han recomendado otros usuarios.
74U n3U7r1no
Ok, disculpas, es posible que desees agregar algo al principio que resuma el enfoque y las razones para usarlo.
combinatoria
@combinatorial Gracias
74U n3U7r1no