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.
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:
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.
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:
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]];
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;
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;
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;
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;
Een beeldcontext is een bitmap-gebaseerde grafische context die u kunt gebruiken om afbeeldingen te tekenen en te manipuleren. UIView
de 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.
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.
We kunnen de inhoud van de beeldcontext, de momentopname van de weergave, krijgen door aan te roepen UIGraphicsGetImageFromCurrentImageContext
. Deze functie retourneert een UIImage
voorwerp.
Nadat de momentopname is gemaakt, verwijderen we de grafische context uit de stapel door op te roepen UIGraphicsEndImageContext
.
Zodra u de momentopname heeft, kunnen we deze vervagen met behulp van een aantal technieken. In deze tutorial zal ik drie technieken behandelen:
UIImage + ImageEffects
categorieCore 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:
CIImage
object van de UIImage
voorwerp. Wanneer u met het Core Image-framework werkt, worden afbeeldingen weergegeven door CIImage
voorwerpen.CIAffineClamp
, voordat u het Gaussiaanse vervagingfilter toepast.CIGaussianBlur
filter samen met een vervagingstraal van 30
.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
.UIImage
object uit de beeldcontext en verwijder de beeldcontext.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:
#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.
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];
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.
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:
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.
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.