Vista sfocata in stile iOS 7


113

Qualcuno sa di controlli che replicheranno le visualizzazioni sfocate in stile iOS7.

Presumo che ci possa essere una sorta di sottoclasse UIView che replicherà il comportamento.

Sto parlando di queste visualizzazioni di tipo che sfocano lo sfondo in modo estremamente spesso in modo che abbiano effetti di trascinamento dalla visualizzazione dello sfondo.

inserisci qui la descrizione dell'immagine


6
GPUImage potrebbe aiutare.
Maarten

@Anil bene, allora la domanda sarà quando verrà rilasciato l'SDK ios7 come posso farlo senza limitare la mia app solo a ios7;).
termina l'


1
Apple ha rilasciato una categoria UIImage che fa esattamente questo. Sto solo cercando di trovarlo.
Fogmeister

1
Il codice è collegato dalla sessione WWDC 201. È pubblico su GitHub Non riesco proprio a trovarlo atm.
Fogmeister

Risposte:


40

Potresti essere in grado di modificare qualcosa come RWBlurPopover di Bin Zhang per farlo. Quel componente usa la mia GPUImage per applicare una sfocatura gaussiana ai componenti sottostanti, ma potresti usare altrettanto facilmente un CIGaussianBlur per lo stesso. GPUImage potrebbe essere un pelo più veloce però .

Quel componente si basa sulla tua capacità di catturare la vista dietro quella che stai presentando, tuttavia, e potrebbe avere problemi con le visualizzazioni che si animano dietro questo contenuto. La necessità di fare un viaggio attraverso Core Graphics per rasterizzare la vista in background rallenterà le cose, quindi probabilmente non abbiamo un accesso sufficientemente diretto per essere in grado di farlo in modo performante per le sovrapposizioni su viste animate.

Come aggiornamento di quanto sopra, di recente ho rielaborato le sfocature in GPUImage per supportare raggi variabili, consentendo la replica completa delle dimensioni della sfocatura nella vista del centro di controllo di iOS 7. Da questo, ho creato la classe GPUImageiOS7BlurFilter che incapsula la corretta dimensione della sfocatura e la correzione del colore che Apple sembra utilizzare qui. Ecco come la sfocatura di GPUImage (a destra) si confronta con la sfocatura incorporata (a sinistra):

Sfocatura di Apple Sfocatura di GPUImage

Uso un downsampling / upsampling 4X per ridurre il numero di pixel su cui deve operare la sfocatura gaussiana, quindi un iPhone 4S può sfocare l'intero schermo in circa 30 ms utilizzando questa operazione.

Hai ancora la sfida di come inserire i contenuti in questa sfocatura dalle visualizzazioni dietro questa in modo performante.


Quindi come pensi che Apple stia riuscendo a risolverlo? Se apri l'app Fotocamera e apri il Centro di controllo (la schermata delle impostazioni dal basso), la sfocatura segue ciò che vede la Fotocamera.
Pupazzo di neve

2
@maq - Aiuta ad avere accesso nascosto a tutto il sistema. Ciò che può fare chi sviluppa il sistema operativo è molto diverso da ciò che le interfacce pubbliche ci consentono di fare.
Brad Larson

3
@maq - La fotocamera si alimenta specificamente, sì. Un modo per farlo sarebbe usare GPUImage per inserire i fotogrammi della telecamera (tramite AV Foundation) e quindi avere quell'output sia su GPUImageView per l'output della telecamera live e poi in parallelo essere alimentato in una sfocatura gaussiana (e possibilmente un ritaglio per abbinare la posizione della vista sfocata) e quell'output su un'altra GPUImageView che visualizzerebbe il contenuto sfocato dietro i tuoi controlli. Ciò è possibile perché abbiamo un percorso veloce dai frame della fotocamera a OpenGL ES, ma non abbiamo nulla di simile per gli elementi dell'interfaccia utente generici.
Brad Larson

1
Sto catturando uno screenshot di una UIView in modo programmatico e usando GPUImageGaussianBlurFilter per provare a creare un effetto simile, ma il risultato è molto diverso da quello in stile Apple. Il filtro sembra sfocare in una griglia, con quadrati visibili ovunque, dove quello di Apple è solo un foglio liscio.
Pupazzo di neve

1
@maq - Assicurati di utilizzare il codice più recente dal repository, perché prima c'era un bug con raggi di sfocatura elevati. Detto questo, la sfocatura campiona solo un'area di 9 pixel per impostazione predefinita, quindi se aumenti il ​​moltiplicatore per la sfocatura oltre quel punto inizierai a vedere artefatti dal saltare i pixel. Questo viene fatto per motivi di prestazioni, ma è possibile modificare gli shader di vertici e frammenti per campionare un numero maggiore di pixel. Oppure prova ad applicare un CIGaussianBlur, che ha un'implementazione di sfocatura più generalizzata. Uno di questi giorni, estenderò questa sfocatura a raggi più grandi.
Brad Larson

28

Sto usando FXBlurViewche funziona alla grande su 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]

L'ho aggiunto usando:

FXBlurView *blurView = [[FXBlurView alloc] initWithFrame:CGRectMake(50, 50, 150, 150)];
[self.blurView setDynamic:YES];
[self.view addSubview:self.blurView];

2
C'è qualche trucco nell'usare FXBlurView? L'ho provato, ma abbiamo ottenuto visualizzazioni lente su un iPhone 5. Il loro progetto demo funziona bene. Abbastanza strano.
Cris

Dipende da quello che vuoi fare. Quando ho posato la parte FXBlurViewsuperiore di un UIScrollViewho ottenuto anche un risultato lento. Credo che questo abbia a che fare con il modo in cui viene aggiunta la sfocatura. Apple sta, se non mi sbaglio, accede direttamente alla GPU quando si utilizza la sua sfocatura, cosa che non possiamo fare come sviluppatori. Quindi, la soluzione @cprcrack è in realtà la soluzione migliore qui.
Paul Peelen

2
Come hai gestito le rotazioni del dispositivo con FXBlurView? Al momento sto presentando una finestra di dialogo modale; la finestra di dialogo stessa ruota bene ma lo sfondo è schiacciato nel modo sbagliato (deve essere aggiornato sostanzialmente dopo la rotazione).
fatuhoku

1
ovviamente, FXBlurView è una buona opzione, ma quando c'è questione di utilizzo della CPU. di quanto preferisco altri blurView. lo uso nel mio UICollectionVIew e UITableView ma aumenta l'utilizzo della CPU. nella prossima esecuzione commento quelle allocazioni e diventa normale. spero, questo aiuterà qualcuno.
Vatsal Shukla,

27

ATTENZIONE: qualcuno nei commenti ha affermato che Apple rifiuta le app che utilizzano questa tecnica. NON è successo a me, ma solo per la tua considerazione.

Questo potrebbe sorprenderti, ma puoi usare una UIToolbar , che include già quell'effetto standard (solo iOS 7+). Nella visualizzazione del controller di visualizzazioneDidLoad:

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

1
Sì, mi ha sorpreso. Ho verificato, questa idea funziona. Ho apportato solo un cambio di riga in viewDidLoadquesto modo. - (void) viewDidLoad {[super viewDidLoad]; self.view = [[UIToolbar alloc] initWithFrame: CGRectZero]; } Nel mio caso, impagino le mie viste in modo programmatico (vecchio stile). Voto a favore di questa soluzione perché UIToolbar eredita UIView quindi fondamentalmente non vedo alcun problema in questa soluzione. Proverò di più man mano che procederò con lo sviluppo e testerò questa soluzione.
Ashok

Questa è un'ottima idea e sembra funzionare davvero bene. Vorrei avere più controllo, ma questo è il massimo! Detto questo, @SudhirJonathan ha menzionato un link sopra dove l'autore porta questo al livello successivo: RUBA IL CALAYER da un UIToolBar e lo riutilizza! Brillante!
David H

2
Veramente? Su quali basi? Non utilizza alcuna API privata e se tutti i modi innovativi di fare le cose venissero rifiutati, molti effetti non sarebbero possibili ...
TheEye

Ha funzionato sul mio iPhone iOS 7.1
marsant

C'è un modo per "smorzare" la sfocatura?
maxisme


13

Il nuovo modo migliore per ottenere una sovrapposizione sfocata è utilizzare la nuova funzionalità UIVisualEffectView di iOS 8.

UIBlurEffect *effect = [UIBlurEffect effectWithStyle:UIBlurEffectStyleLight];

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

bluredView.frame = self.view.bounds;

[self.view addSubview:bluredView];

UIBlurEffect supporta tre tipi di stile. Scuro, Chiaro ed ExtraLight.


1

È possibile creare una classe con un UIToolBar che è una sottoclasse di UIView e istanziarlo in un controller di visualizzazione separato. Questo approccio mostra una UIToolBar traslucida (sottoclasse da UIView) che fornisce feedback in tempo reale (in questo caso per un 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 volta che l'UIView sopra è stato personalizzato, vai avanti e crea una classe che sia una sottoclasse di un ViewController. Di seguito ho creato una classe che utilizza una sessione AVCapture. Devi usare AVCaptureSession per sovrascrivere la configurazione della fotocamera incorporata di Apple. Quindi puoi sovrapporre la UIToolBar tranclucent dalla classe 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

La risposta sembra essere completamente estranea alla domanda.
combinatoria

@combinatorial Questo è uno dei modi più efficienti per aggiungere una visualizzazione trasparente a un altro controller di visualizzazione. Ho incluso il codice AVCapture per mostrare che potrebbe essere utilizzato per feedback dal vivo piuttosto che aggiungere semplicemente un'immagine di sfondo sfocata, come consigliato da altri utenti.
74U n3U7r1no

Ok, scusa, potresti voler aggiungere qualcosa all'inizio che riassuma l'approccio e le ragioni per usarlo.
combinatoria

@combinatorial Thanks
74U n3U7r1no
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.