Vue floue de style iOS 7

113

Est-ce que quelqu'un connaît des contrôles qui reproduiront les vues floues de style iOS7.

Je suppose qu'il peut y avoir une sorte de sous-classe UIView qui reproduira le comportement.

Je parle de ces vues de type qui brouillent l'arrière-plan de manière extrêmement épaisse afin qu'elles aient des effets d'attraction de la vue d'arrière-plan.

entrez la description de l'image ici

endy
la source
6
GPUImage peut vous aider.
Maarten
@Anil eh bien, la question sera de savoir quand le SDK ios7 sera publié, comment puis-je le faire sans restreindre mon application à ios7 uniquement;).
endy
1
Apple a publié une catégorie UIImage qui fait exactement cela. J'essaye juste de le trouver.
Fogmeister
1
Le code est lié à partir de la session 201 de la WWDC. Il est public sur github. Je ne peux pas le trouver atm.
Fogmeister

Réponses:

40

Vous pourrez peut-être modifier quelque chose comme RWBlurPopover de Bin Zhang pour ce faire. Ce composant utilise mon GPUImage pour appliquer un flou gaussien aux composants en dessous, mais vous pouvez tout aussi facilement utiliser un CIGaussianBlur pour le même. GPUImage pourrait cependant être un poil plus rapide .

Cependant, ce composant dépend de votre capacité à capturer la vue derrière celle que vous présentez et peut avoir des problèmes avec les vues qui s'animent derrière ce contenu. La nécessité de parcourir Core Graphics pour pixelliser la vue d'arrière-plan ralentira les choses, nous n'avons donc probablement pas un accès suffisamment direct pour pouvoir le faire de manière performante pour les superpositions sur des vues animées.

En tant que mise à jour de ce qui précède, j'ai récemment retravaillé les flous dans GPUImage pour prendre en charge des rayons variables, permettant la réplication complète de la taille du flou dans la vue du centre de contrôle d'iOS 7. À partir de là, j'ai créé la classe GPUImageiOS7BlurFilter qui encapsule la taille de flou et la correction des couleurs appropriées qu'Apple semble utiliser ici. Voici comment le flou de GPUImage (à droite) se compare au flou intégré (à gauche):

Le flou d'Apple Le flou de GPUImage

J'utilise un sous-échantillonnage / suréchantillonnage 4X pour réduire le nombre de pixels sur lesquels le flou gaussien doit fonctionner, de sorte qu'un iPhone 4S peut brouiller tout l'écran en environ 30 ms en utilisant cette opération.

Vous avez toujours le défi de savoir comment tirer du contenu dans ce flou à partir des vues derrière celui-ci de manière performante.

Brad Larson
la source
Alors, comment pensez-vous qu'Apple y parvient? Si vous ouvrez l'application Appareil photo et ouvrez le Centre de contrôle (l'écran des paramètres en partant du bas), le flou suit ce que voit l'appareil photo.
Snowman
2
@maq - Cela aide d'avoir un accès sous le capot à tout sur le système. Ce que quelqu'un qui développe le système d'exploitation peut faire est très différent de ce que les interfaces publiques nous permettent de faire.
Brad Larson
3
@maq - La caméra se nourrit spécifiquement, oui. Une façon de le faire serait d'utiliser GPUImage pour extraire les cadres de la caméra (via AV Foundation), puis de faire en sorte que la sortie soit à la fois vers un GPUImageView pour la sortie de la caméra en direct, puis en parallèle être introduite dans un flou gaussien (et éventuellement un recadrage). pour correspondre à la position de la vue floue) et cette sortie vers un autre GPUImageView qui afficherait le contenu flou derrière vos contrôles. Cela est possible car nous avons un chemin rapide entre les cadres de caméra et OpenGL ES, mais nous n'avons rien de similaire pour les éléments d'interface utilisateur génériques.
Brad Larson
1
Je prends une capture d'écran d'un UIView par programmation et j'utilise GPUImageGaussianBlurFilter pour essayer de créer un effet similaire, mais le résultat est très différent de celui de style Apple. Le filtre semble flou dans une grille, avec des carrés visibles partout, où celui d'Apple n'est qu'une feuille lisse.
Snowman
1
@maq - Assurez-vous que vous utilisez le dernier code du référentiel, car il y avait un bogue à des rayons de flou élevés auparavant. Cela dit, le flou n'échantillonne qu'une zone de 9 pixels par défaut, et donc si vous augmentez le multiplicateur du flou au-delà de ce point, vous commencerez à voir des artefacts en sautant des pixels. Ceci est fait pour des raisons de performances, mais vous pouvez modifier les shaders de sommets et de fragments pour échantillonner un plus grand nombre de pixels. Cela, ou essayez d'appliquer un CIGaussianBlur, qui a une implémentation de flou plus généralisée. Un de ces jours, je vais étendre ce flou à des rayons plus grands.
Brad Larson
28

J'utilise FXBlurViewce qui fonctionne très bien sur 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]

Je l'ai ajouté en utilisant:

FXBlurView *blurView = [[FXBlurView alloc] initWithFrame:CGRectMake(50, 50, 150, 150)];
[self.blurView setDynamic:YES];
[self.view addSubview:self.blurView];
Paul Peelen
la source
2
Y a-t-il une astuce pour utiliser FXBlurView? Je l'ai essayé, mais nous avons obtenu des vues décalées sur un iPhone 5. Leur projet de démonstration fonctionne très bien. Assez bizarre.
Cris
Cela dépend de ce que vous voulez faire. Quand je pose FXBlurViewle dessus UIScrollViewsur un, j'obtiens également un résultat décalé. Je pense que cela a à voir avec la façon dont le flou est ajouté. Apple, si je ne me trompe pas, accède directement au GPU en utilisant son propre flou, ce que nous ne pouvons pas faire en tant que développeurs. Par conséquent, la solution @cprcrack est en fait la meilleure solution ici.
Paul Peelen
2
Comment avez-vous géré les rotations d'appareils avec FXBlurView? Je présente un dialogue modal pour le moment; le dialogue lui-même tourne correctement mais le fond est écrasé dans le mauvais sens (il doit être mis à jour après la rotation en gros).
fatuhoku
1
bien sûr, FXBlurView est une bonne option, mais quand il y a une question d'utilisation du processeur. que je préfère d'autres blurView. J'utilise ceci dans mon UICollectionVIew et UITableView mais cela augmente mon utilisation du processeur. dans la prochaine exécution, je commente ces allocations et cela devient normal. j'espère que cela aidera quelqu'un.
Vatsal Shukla du
27

AVERTISSEMENT: quelqu'un dans les commentaires a déclaré qu'Apple rejette les applications utilisant cette technique. Cela ne m'est pas arrivé, mais juste pour votre considération.

Cela peut vous surprendre, mais vous pouvez utiliser une UIToolbar , qui inclut déjà cet effet standard (uniquement iOS 7+). Dans vous affichez le viewDidLoad du contrôleur:

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
la source
1
Oui, cela m'a surpris. J'ai vérifié, cette idée fonctionne. J'ai fait juste un changement de ligne viewDidLoadcomme ça. - (void) viewDidLoad {[super viewDidLoad]; self.view = [[UIToolbar alloc] initWithFrame: CGRectZero]; } Dans mon cas, je mets en page mes vues par programmation (ancien style). Je vote pour cette solution car UIToolbar hérite de UIView donc fondamentalement, je ne vois aucun problème dans cette solution. Je testerai davantage au fur et à mesure que j'avancerai dans le développement et testerai cette solution.
Ashok
C'est une excellente idée et cela semble très bien fonctionner. J'aurais aimé avoir plus de contrôle, mais c'est aussi bien que possible! Cela dit, @SudhirJonathan a mentionné un lien ci-dessus où l'auteur amène cela au niveau suivant - IL Vole LE CALAYER d'un UIToolBar et le réutilise! Brillant!
David H
2
Vraiment? Pour quels motifs? Il n'utilise aucune API privée, et si toutes les façons innovantes de faire les choses étaient rejetées, beaucoup d'effets ne seraient pas possibles ...
TheEye
A travaillé sur mon iPhone iOS 7.1
marsant
Existe-t-il un moyen de "réduire" le flou?
maxisme
13

Depuis iOS8, vous pouvez utiliser UIBlurEffect .

Il existe de bons exemples sur iOS8Sampler avec UIBlurEffect et UIVibrancyEffect .

VivienCormier
la source
2
Pour les paresseux: UIVisualEffect *blurEffect = [UIBlurEffect effectWithStyle:UIBlurEffectStyleDark]; UIVisualEffectView *blurView = [[UIVisualEffectView alloc] initWithEffect:blurEffect];
Ric Santos
13

La meilleure nouvelle façon d'obtenir une superposition estompée est d'utiliser la nouvelle fonctionnalité iOS 8 UIVisualEffectView.

UIBlurEffect *effect = [UIBlurEffect effectWithStyle:UIBlurEffectStyleLight];

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

bluredView.frame = self.view.bounds;

[self.view addSubview:bluredView];

UIBlurEffect prend en charge trois types de style. Sombre, clair et extra-léger.

Jeanette Müller
la source
1

Vous pouvez créer une classe avec un UIToolBar qui est une sous-classe de UIView et l'instancier dans un contrôleur de vue distinct. Cette approche démontre un UIToolBar translucide (sous-classé par UIView) qui fournit des commentaires en direct (dans ce cas pour 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

Une fois que l'UIView ci-dessus a été personnalisé, continuez et créez une classe qui est une sous-classe d'un ViewController. Ci-dessous, j'ai créé une classe qui utilise une session AVCapture. Vous devez utiliser AVCaptureSession pour remplacer la configuration de la caméra intégrée d'Apple. Ainsi, vous pouvez superposer le tranclucent UIToolBar de la 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
74U n3U7r1no
la source
La réponse semble être totalement indépendante de la question.
combinatoire du
@combinatorial C'est l'un des moyens les plus efficaces d'ajouter une vue transparente à un autre contrôleur de vue. J'ai inclus le code AVCapture pour montrer qu'il pouvait être utilisé pour des commentaires en direct plutôt que d'ajouter simplement une image d'arrière-plan floue, comme d'autres utilisateurs l'ont recommandé.
74U n3U7r1no
Ok, excuses, vous voudrez peut-être ajouter quelque chose au début qui résume l'approche et les raisons de son utilisation.
combinatoire du
@combinatorial Thanks
74U n3U7r1no