Blur-effecten toevoegen aan iOS

Invoering

Met iOS 7 zagen we een verschuiving in het ontwerpparadigma van Apple voor mobiele apparaten. Ze hebben niet alleen het zogenaamde platte ontwerp overgenomen, maar Apple heeft zelf ook een paar elementen aan dit patroon toegevoegd. Een van deze toevoegingen is het gebruik van wazig-doorschijnende achtergronden om het begrip diepte en context over te brengen. Nemen Controle Centrum het vervaagt bijvoorbeeld de inhoud van het uitzicht erachter wanneer het wordt opgetrokken. Dit geeft de gebruiker het gevoel dat het gepositioneerd is bovenstaande andere inhoud op het scherm en verdient aandacht. Dit gebeurt zonder dat de gebruiker uit het oog verliest waar ze zich in de app bevindt.

Hoewel onscherpte en translucentie overal in het besturingssysteem op iOS 7 worden gebruikt, biedt de iOS SDK ons geen API's om hetzelfde effect te bereiken. In deze zelfstudie bespreek ik enkele methoden om wazige weergaven te maken door de onderstaande voorbeeld-app te maken.

Onze voorbeeld-app heeft onderaan een weergave, die kan worden onthuld door deze omhoog te trekken. De weergave is doorschijnend en vervaagt de inhoud die eronder in de weergavehiërarchie staat, vergelijkbaar met Control Center op iOS 7.

1. Projectinstelling

Overzicht

De app die we gaan bouwen, geeft een foto weer met de naam van de foto en de auteur, weergegeven in een witte cirkel. Er is ook een kleine rechthoekige weergave onder aan het scherm die de foto vervaagt en die kan worden omhooggetrokken om extra informatie over de foto weer te geven.

Ik ga ervan uit dat je al weet hoe te werken met elementaire elementen van de gebruikersinterface, zoals weergaven, afbeeldingen en schuifweergaven. In deze zelfstudie concentreren we ons op de weergavehiërarchie en de weergaven die we nodig hebben om het vervagingseffect te maken.

Bekijk de bovenstaande afbeelding. Het trekt de weergavehiërarchie uit elkaar om het waaseffect te creëren dat we zoeken. De belangrijkste componenten zijn:

  • Achtergrondweergave: In deze weergave worden de foto en credits weergegeven. Dit is het beeld dat we gaan vervagen.
  • Wazig beeld: Deze weergave bevat een vervaagde versie van de inhoud van de achtergrondweergave.
  • Bekijk masker: Het weergavemasker is een ondoorzichtige weergave die we gebruiken om de wazige afbeelding te maskeren.
  • Scroll View: De schuifweergave is de weergave die aanvullende informatie over de foto bevat. De offset van het schuifaanzicht wordt gebruikt om de hoogte van het maskeraanzicht te vergroten of te verkleinen. Dit zal ertoe leiden dat de wazige afbeelding zichzelf weergeeft als reactie op het scrollen van de schuifweergave.

Middelen

Alle afbeeldingen, frameworks en andere bestanden die nodig zijn voor deze tutorial zijn opgenomen in de bronbestanden van deze tutorial. Kloon de repository van GitHub of download de bronbestanden om mee te volgen.

2. De gebruikersinterface maken

1. Overzicht

Open RootViewController.m in Xcode en bekijk het loadView methode. U kunt in vogelvlucht zien hoe de gebruikersinterface is ingedeeld door te kijken naar de implementatie van deze methode. Er zijn drie hoofdsubviews in onze applicatie:

  • Header View: Toont de naam van de toepassing
  • Inhoudsoverzicht: Geeft de foto en credits weer
  • Scroll View: Bevat aanvullende informatie over een schuifbaar wazig beeld

In plaats van de loadView methode met initialiseren en configureren van de subweergaven, helper-methoden worden gebruikt om het zware werk te doen:

// inhoudweergave [self.view addSubview: [self createContentView]]; // header view [self.view addSubview: [self createHeaderView]]; // scrolweergave [self.view addSubview: [self createScrollView]];

2. De kopweergave maken

De koptekstweergave bevat een doorschijnende rechthoek en een tekstlabel met de naam van de toepassing.

- (UIView *) createHeaderView UIView * headerView = [[UIView alloc] initWithFrame: CGRectMake (0, 0, self.view.frame.size.width, 60)]; headerView.backgroundColor = [UIColor colorWithRed: 229 / 255.0 groen: 39 / 255.0 blauw: 34 / 255.0 alpha: 0.6]; UILabel * title = [[UILabel alloc] initWithFrame: CGRectMake (0, 20, self.view.frame.size.width, 40)]; title.text = @ "Dynamic Blur Demo"; ... [headerView addSubview: title]; return headerView; 

3. De inhoudsweergave maken

De inhoudsweergave geeft de foto weer en bevat ook de fotokredieten in een witte cirkel.

- (UIView *) createContentView UIView * contentView = [[UIView alloc] initWithFrame: self.view.frame]; // Achtergrondafbeelding UIImageView * contentImage = [[UIImageView-toewijzing] initWithFrame: contentView.frame]; contentImage.image = [UIImage imageNamed: @ "demo-bg"]; [contentView addSubview: contentImage]; // Photo credits UIView * creditsViewContainer = [[UIView alloc] initWithFrame: CGRectMake (self.view.frame.size.width / 2 - 65, 335, 130, 130)]; metaViewContainer.backgroundColor = [UIColor whiteColor]; metaViewContainer.layer.cornerRadius = 65; [contentView addSubview: creditsViewContainer]; UILabel * photoTitle = [[UILabel alloc] initWithFrame: CGRectMake (0, 54, 130, 18)]; photoTitle.text = @ "Peach Garden"; ... [metaViewContainer addSubview: photoTitle]; UILabel * photographer = [[UILabel alloc] initWithFrame: CGRectMake (0, 72, 130, 9)]; photographer.text = @ "door Cas Cornelissen"; ... [metaViewContainer addSubview: photographer]; return contentView; 

4. De bladerweergave maken

De schuifweergave bevat aanvullende informatie over de foto en een wazige versie van de foto. De schuifweergave is ongeveer twee keer de lengte van het scherm, waarbij de onderste helft de tekstweergave en de afbeeldingsweergave bevat. Door paging in de scrollweergave in te schakelen, wordt de inhoud van de scrollweergave naar de boven- of onderzijde van de weergave afgebroken, afhankelijk van de offset van de schuifweergave.

- (UIView *) createScrollView UIView * containerView = [[UIView alloc] initWithFrame: self.view.frame]; blurredBgImage = [[UIImageView alloc] initWithFrame: CGRectMake (0, 0, self.view.frame.size.width, 568)]; [blurredBgImage setContentMode: UIViewContentModeScaleToFill]; [containerView addSubview: blurredBgImage]; UIScrollView * scrollView = [[UIScrollView-toewijzing] initWithFrame: self.view.frame]; scrollView.contentSize = CGSizeMake (self.view.frame.size.width, self.view.frame.size.height * 2 - 110); scrollView.pagingEnabled = YES; ... [containerView addSubview: scrollView]; UIView * slideContentView = [[UIView-toewijzing] initWithFrame: CGRectMake (0, 518, self.view.frame.size.width, 508)]; slideContentView.backgroundColor = [UIColor clearColor]; [scrollView addSubview: slideContentView]; UILabel * slideUpLabel = [[UILabel alloc] initWithFrame: CGRectMake (0, 6, self.view.frame.size.width, 50)]; slideUpLabel.text = @ "Foto-informatie"; ... [slideContentView addSubview: slideUpLabel]; UIImageView * slideUpImage = [[UIImageView alloc] initWithFrame: CGRectMake (self.view.frame.size.width / 2 - 12, 4, 24, 22.5)]; slideUpImage.image = [UIImage imageNamed: @ "up-arrow.png"]; [slideContentView addSubview: slideUpImage]; UITextView * detailsText = [[UITextView alloc] initWithFrame: CGRectMake (25, 100, 270, 350)]; detailsText.text = @ "Lorem ipsum ... laborum"; ... [slideContentView addSubview: detailsText]; container retourneren; 

3. Een momentopname maken

Om een ​​weergave onscherp te maken, moeten we eerst een momentopname van de inhoud maken en deze klaar hebben in de vorm van een afbeelding. we kunnen dan de afbeelding vervagen en gebruiken als de achtergrond van een andere weergave. Laten we eerst eens kijken hoe we een momentopname kunnen maken van de inhoud van a UIView voorwerp.

In iOS 7 heeft Apple een nieuwe methode toegevoegd UIView voor het maken van snapshots van de inhoud van een weergave, drawViewHierarchyInRect: afterScreenUpdates:. Deze methode maakt een momentopname van de inhoud van de weergave, inclusief eventuele subweergaven.

Laten we een methode definiëren in de ViewController klasse die een a accepteert UIView object en retourneert een UIImage, een momentopname van de inhoud van de weergave.

- (UIImage *) takeSnapshotOfView: (UIView *) view UIGraphicsBeginImageContext (CGSizeMake (view.frame.size.width, view.frame.size.height)); [view drawViewHierarchyInRect: CGRectMake (0, 0, view.frame.size.width, view.frame.size.height) afterScreenUpdates: YES]; UIImage * image = UIGraphicsGetImageFromCurrentImageContext (); UIGraphicsEndImageContext (); afbeelding retourneren; 

Stap 1: begin een nieuwe beeldcontext

Een beeldcontext is een bitmap-gebaseerde grafische context die u kunt gebruiken om afbeeldingen te tekenen en te manipuleren. UIViewde nieuwe methode drawViewHierarchyInRect: afterScreenUpdates: rastert het UIView en tekent de inhoud ervan in de huidige beeldcontext.

Dit betekent dat voordat we deze methode aanroepen, we eerst een nieuwe beeldcontext moeten maken door aan te roepen UIGraphicsBeginImageContext, doorgeven van de vereiste grootte voor de beeldcontext.

Stap 2: Maak een momentopname

Met de beeldcontext ingesteld, kunnen we de view's bellen drawViewHierarchyInRect: afterScreenUpdates: methode. Het tweede argument geeft aan of de momentopname de huidige inhoud van de weergave moet bevatten of recente wijzigingen moet bevatten voordat de snapshot wordt gemaakt.

Stap 3: Maak een afbeelding van de beeldcontext

We kunnen de inhoud van de beeldcontext, de momentopname van de weergave, krijgen door aan te roepen UIGraphicsGetImageFromCurrentImageContext. Deze functie retourneert een UIImage voorwerp.

Stap 4: beëindig beeldcontext

Nadat de momentopname is gemaakt, verwijderen we de grafische context uit de stapel door op te roepen UIGraphicsEndImageContext.

4. Vervaging van de momentopname

Zodra u de momentopname heeft, kunnen we deze vervagen met behulp van een aantal technieken. In deze tutorial zal ik drie technieken behandelen:

  • vervaging met het Core Image-framework
  • vervaging met het GPUImage-framework van Brad Larson
  • vervagen met behulp van Apple's UIImage + ImageEffects categorie

Optie 1: kernafbeelding

Core Image is een beeldverwerkingsraamwerk dat is ontwikkeld en wordt onderhouden door Apple. Het maakt gebruik van een GPU- of CPU-renderingpad om afbeeldingen bijna in realtime te verwerken.

Core Image biedt ons een verscheidenheid aan filters die kunnen worden gebruikt om bewerkingen uit te voeren, variërend van het wijzigen van de tint of verzadiging van een afbeelding tot gezichtsherkenning.

CIGaussianBlur is een van de filters in het Core Image-framework en kan worden gebruikt om afbeeldingen te vervagen. Het vervagen van een afbeelding met Core Image is vrij eenvoudig, zoals u hieronder kunt zien.

- (UIImage *) blurWithCoreImage: (UIImage *) sourceImage CIImage * inputImage = [CIImage imageWithCGImage: sourceImage.CGImage]; // Affine-Clamp-filter toepassen om het beeld uit te rekken zodat het niet // er gekrompen uitziet wanneer gaussiaanse vervaging wordt toegepast CGAffineTransform transform = CGAffineTransformIdentity; CIFilter * clampFilter = [CIFilter filterWithName: @ "CIAffineClamp"]; [clampFilter setValue: inputImage forKey: @ "inputImage"]; [clampFilter setValue: [NSValue valueWithBytes: & transform objCType: @encode (CGAffineTransform)] forKey: @ "inputTransform"]; // Gaussiaans vervagingfilter toepassen met een straal van 30 CIFilter * gaussianBlurFilter = [CIFilter filterWithName: @ "CIGaussianBlur"]; [gaussianBlurFilter setValue: clampFilter.outputImage forKey: @ "inputImage"]; [gaussianBlurFilter setValue: @ 30 forKey: @ "inputRadius"]; CIContext * context = [CIContext contextWithOptions: nil]; CGImageRef cgImage = [context createCGImage: gaussianBlurFilter.outputImage fromRect: [inputImage extent]]; // Stel de uitvoercontext in. UIGraphicsBeginImageContext (self.view.frame.size); CGContextRef outputContext = UIGraphicsGetCurrentContext (); // Beeldcoördinaten omkeren CGContextScaleCTM (outputContext, 1.0, -1.0); CGContextTranslateCTM (outputContext, 0, -self.view.frame.size.height); // Teken het basisbeeld. CGContextDrawImage (outputContext, self.view.frame, cgImage); // Witte tint toepassen CGContextSaveGState (outputContext); CGContextSetFillColorWithColor (outputContext, [UIColor colorWithWhite: 1 alpha: 0.2] .CGColor); CGContextFillRect (outputContext, self.view.frame); CGContextRestoreGState (outputContext); // Uitvoerbeeld is gereed. UIImage * outputImage = UIGraphicsGetImageFromCurrentImageContext (); UIGraphicsEndImageContext (); return outputImage; 

Laten we het bovenstaande codeblok afbreken:

  • We maken eerst een CIImage object van de UIImage voorwerp. Wanneer u met het Core Image-framework werkt, worden afbeeldingen weergegeven door CIImage voorwerpen.
  • Afhankelijk van de vervagingstraad zal het toepassen van een Gaussiaanse vervaging op een afbeelding de afbeelding enigszins verkleinen. Om dit probleem te omzeilen, rekken we de afbeelding een beetje uit door een ander filter toe te passen, CIAffineClamp, voordat u het Gaussiaanse vervagingfilter toepast.
  • We nemen de output en geven deze door aan de CIGaussianBlur filter samen met een vervagingstraal van 30.
  • We zouden de uitvoer kunnen nemen, omzetten in een CGImage,  en gebruik het in onze applicatie. We voegen echter een witte tint toe aan de afbeelding om ervoor te zorgen dat de beschrijving van de foto duidelijk leesbaar is. Om een ​​witte tint toe te voegen, voegen we een semi-transparante witte vulling toe aan de afbeelding. Hiertoe maken we een nieuwe afbeeldingscontext en vullen deze met een witte kleur met een alpha-waarde van 0.2.
  • Zoals we eerder zagen, krijgen we een UIImage object uit de beeldcontext en verwijder de beeldcontext.

Optie 2: GPUImage

GPUImage is een open-source iOS-framework voor beeld- en videoverwerking, gemaakt en onderhouden door Brad Larson. Het bevat een verzameling GPU-versnelde filters die kunnen worden toegepast op afbeeldingen, livecameravideo en films.

Het GPUImage-framework is opgenomen in de bronbestanden van deze zelfstudie, maar het toevoegen van het framework aan uw eigen projecten is heel eenvoudig:

  1. Begin met het downloaden van het framework of het klonen van de repository vanuit GitHub.
  2. Open een terminalvenster, ga naar de GPUImage-map en voer het build-script uit build.sh om het raamwerk te compileren.
  3. Kopieer de GPUImage.framework van de bouwen map naar de map van uw project en sleep het vervolgens naar de map Project Navigator.
  4. U kunt dan het GPUImage-framework in uw project gebruiken door de framework-headers te importeren, #importeren .

Het GPUImage-framework bevat filters die lijken op die in het Core Image-framework. Voor onze voorbeeldtoepassing zijn we geïnteresseerd in twee filters, , GPUImageGaussianBlurFilter en GPUImageiOSBlurFilter.

- (UIImage *) blurWithGPUImage: (UIImage *) sourceImage // Gaussian Blur GPUImageGaussianBlurFilter * blurFilter = [[GPUImageGaussianBlurFilter alloc] init]; blurFilter.blurRadiusInPixels = 30.0; return [blurFilter imageByFilteringImage: sourceImage]; 

Zoals u kunt zien, zijn GPUImage-filters eenvoudiger te gebruiken dan die van het Core Image-framework. Nadat u het filterobject hebt geïnitialiseerd, hoeft u alleen nog het filter te configureren en het te voorzien van een afbeelding waarop het filter moet worden toegepast. De imageByFilteringImage: methode geeft a terug UIImage voorwerp.

In plaats van de GPUImageGaussianblur klasse, je zou ook de GPUImageiOSblur klasse zoals zo:

 // iOS Blur GPUImageiOSBlurFilter * blurFilter = [[GPUImageiOSBlurFilter alloc] init]; blurFilter.blurRadiusInPixels = 30.0;

De GPUImageiOSblur klasse repliceert het vervagingseffect dat u in Control Center op iOS 7 ziet. In tegenstelling tot de Core Image-benadering hoeft u dus geen extra code te schrijven om het wazige beeld te tonen.

Optie 3: UIImage + ImageEffects

Tijdens de WWDC van vorig jaar gaf Apple een lezing over Core Image-effecten en -technieken waarin ze een categorie introduceerden UIImage riep ImageEffects. De ImageEffects categorie maakt gebruik van de hoge prestaties van Apple vImage beeldverwerkingsraamwerk, onderdeel van de Versnellen raamwerk, om de nodige berekeningen uit te voeren. Dit maakt het een snelle en gemakkelijke manier om onscherpte op iOS uit te voeren.
De categorie voegt de volgende methoden toe aan de UIImage klasse:

  • applyLightEffect
  • applyExtraLightEffect
  • applyDarkEffect
  • applyTintEffectWithColor:
  • applyBlurWithRadius: tintColor: saturationDeltaFactor: maskImage:

Deze methoden kunnen rechtstreeks op een afbeelding worden aangeroepen om het gewenste blur-effect te bereiken. De applyBlurWithRadius: tintColor: saturationDeltaFactor: maskImage: methode accepteert een aantal argumenten waarmee u de vervagingsbewerking kunt verfijnen.

Je kunt Apple's downloaden ImageEffects voorbeeldproject van de ontwikkelaarswebsite van Apple en gebruik het in uw projecten.

#import "UIImage + ImageEffects.h" ... - (UIImage *) blurWithImageEffects: (UIImage *) afbeelding return [image applyBlurWithRadius: 30 tintColor: [UIColor colorWithWhite: 1 alpha: 0.2] saturation DeltaFactor: 1.5 maskImage: nil]; 

5. Het wazige beeld maskeren

In de voorbeeldapp lijkt het alsof we de foto dynamisch vervagen, maar dat is niet het geval. We gebruiken een trucje genaamd maskeren. In plaats van continu snapshots te maken en ze te vervagen om het gewenste effect te creëren, nemen we slechts één snapshot, vervagen het en gebruiken het in combinatie met een masker.

Zoals te zien in de afbeelding aan het begin van deze tutorial, stemmen we de wazige weergave af op de achtergrondweergave eronder. Vervolgens maken we een nieuwe weergave met een hoogte van 50 punten en een ondoorzichtige achtergrond en plaatsen deze onder aan het scherm. We gebruiken deze weergave om de wazige afbeelding te maskeren.

blurredBgImage.layer.mask = bgMask.layer;

Vervolgens werken we het frame van de maskerweergave bij terwijl de schuifweergave wordt gescrolld. Om dit te doen, implementeren we een van de gedelegeerde methoden van de UIScrollViewDelegate protocol, scrollViewDidScroll:, en werk het frame van het masker bij met betrekking tot de verticale inhoudsverschuiving van het scroll-aanzicht.

-(void) scrollViewDidScroll: (UIScrollView *) scrollView bgMask.frame = CGRectMake (bgMask.frame.origin.x, self.view.frame.size.height - 50 - scrollView.contentOffset.y, bgMask.frame.size.width , bgMask.frame.size.height + scrollView.contentOffset.y); 

Door het masker bij te werken, lijkt het alsof we de foto onder de schuifweergave dynamisch vervagen. Dat is het. U hebt nu een prachtig, blur-effect, vergelijkbaar met het effect dat u ziet in het Control Center op iOS.

6. Prestaties

Met de bovenstaande technieken in gedachten, kun je je afvragen welke de beste is qua prestaties. Om u te helpen beslissen, heb ik wat tests uitgevoerd op een iPhone 5S en een 5C. Bekijk de volgende grafieken.

Deze grafieken vertellen ons het volgende:

  • Het GPUImage-framework presteert het traagst op de iPhone 5C vanwege de tragere GPU. Dit is niet verrassend, omdat het framework sterk afhankelijk is van de GPU.
  • De categorie ImageEffects presteert het beste op beide apparaten. Het is ook interessant om te zien dat de tijd die nodig is voor het vervagen van een afbeelding toeneemt met de vervagingstraal.

Hoewel het vervagen van afbeeldingen nooit langer dan 220 ms duurde op de iPhone 5S, had de iPhone 5C tot 1.3 sec nodig om dezelfde taak uit te voeren. Dit toont duidelijk aan dat vervagingseffecten verstandig en spaarzaam moeten worden gebruikt.

Om de tijd die nodig is voor het vervagen van een afbeelding te verminderen, kunnen we de grootte van de momentopname waarop we het vervagingfilter toepassen, verkleinen. Omdat we wazig zijn en de fijne details van de afbeelding sowieso niet zichtbaar zijn, kunnen we de afbeelding downsamplen zonder in problemen te raken. Om een ​​kleinere momentopname te maken, werken we de implementatie van de takeSnapshotOfView: methode als volgt:

- (UIImage *) takeSnapshotOfView: (UIView *) view CGFloat reductionFactor = 1,25; UIGraphicsBeginImageContext (CGSizeMake (view.frame.size.width / reductionFactor, view.frame.size.height / reductionFactor)); [view drawViewHierarchyInRect: CGRectMake (0, 0, view.frame.size.width / reductionFactor, view.frame.size.height / reductionFactor) afterScreenUpdates: YES]; ... return image; 

Om de tijd die nodig is om de momentopname te vervagen verder te verminderen, kunnen we alternatieve vervagingstechnieken gebruiken, zoals een vervaging van een doos. Hoewel het resultaat anders zal zijn dan dat van een Gaussiaanse vervaging, kost het minder tijd om een ​​afbeelding te vervagen met een vervaging in een doos.

Conclusie

Blur is zonder twijfel een geweldige aanvulling op het ontwerp van de gebruikersinterface op iOS. Hoe mooi de gebruikersinterface van uw toepassing er ook uitziet, als deze niet goed presteert, zullen onscherpte-effecten uw applicatie niet verbeteren.

Op basis van bovenstaande prestatiestatistieken, zien we dat vervaging inderdaad een kostbaar effect is. Maar door de parameters te optimaliseren, zoals de vervagingsradius en de afbeeldingsgrootte, de juiste vervagingstechniek te kiezen en een paar trucs te gebruiken, kunnen we zeer interessante effecten bereiken zonder de prestaties van de toepassing te schaden..

In iOS 8 heeft Apple geïntroduceerd UIVisualEffectView, waarmee ontwikkelaars heel eenvoudig onscherpte en vibratie-effecten op weergaven kunnen toepassen. Als je niet kunt wachten totdat iOS 8 officieel is vrijgegeven, kun je deze effecten testen door de bètaversie van Xcode 6 te downloaden.