Forte De Masque
Chaque fois que vous voulez dessiner un chemin qui se compose d'une forme (ou une série de formes) comme un trou dans une autre forme, la clé est presque toujours à l'aide d'un 'même bizarre d'enroulement de la règle'.
À partir de l' Enroulement des Règles de la section de la de Cacao Dessin Guide:
Une règle d'enroulement est tout simplement un algorithme qui permet de surveiller les informations à propos de chaque région contiguë qui fait le chemin d'ensemble de la zone de remplissage. Un rayon est établi à partir d'un point à l'intérieur d'une région donnée à n'importe quel point à l'extérieur du chemin de limites. Le nombre total de traversé les lignes de chemin (y compris implicite lignes) et la direction de chaque ligne de chemin d'accès sont ensuite interprétés à l'aide des règles qui déterminent si la région doit être rempli.
J'apprécie le fait que la description n'est pas vraiment utile sans les règles de contexte et des diagrammes afin de le rendre plus facile à comprendre donc je vous invite à lire les liens que j'ai fournis ci-dessus. Pour l'amour de la création de notre cercle calque de masque les diagrammes suivants illustrent ce qu'un même bizarre règle d'enroulement nous permet de réaliser:
Non Zéro Règle D'Enroulement
Même Étrange Règle D'Enroulement
Maintenant c'est simplement une question de la création de l'translucide masque à l'aide d'un CAShapeLayer qui peut être repositionné et élargi et contracté par l'utilisateur iteraction.
Code
#import <QuartzCore/QuartzCore.h>
@interface ViewController ()
@property (strong, nonatomic) IBOutlet UIImageView *imageView;
@property (strong) CAShapeLayer *blurFilterMask;
@property (assign) CGPoint blurFilterOrigin;
@property (assign) CGFloat blurFilterDiameter;
@end
@implementation ViewController
// begin the blur masking operation.
- (void)beginBlurMasking
{
self.blurFilterOrigin = self.imageView.center;
self.blurFilterDiameter = MIN(CGRectGetWidth(self.imageView.bounds), CGRectGetHeight(self.imageView.bounds));
CAShapeLayer *blurFilterMask = [CAShapeLayer layer];
// Disable implicit animations for the blur filter mask's path property.
blurFilterMask.actions = [[NSDictionary alloc] initWithObjectsAndKeys:[NSNull null], @"path", nil];
blurFilterMask.fillColor = [UIColor blackColor].CGColor;
blurFilterMask.fillRule = kCAFillRuleEvenOdd;
blurFilterMask.frame = self.imageView.bounds;
blurFilterMask.opacity = 0.5f;
self.blurFilterMask = blurFilterMask;
[self refreshBlurMask];
[self.imageView.layer addSublayer:blurFilterMask];
UITapGestureRecognizer *tapGesture = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(handleTap:)];
[self.imageView addGestureRecognizer:tapGesture];
UIPinchGestureRecognizer *pinchGesture = [[UIPinchGestureRecognizer alloc] initWithTarget:self action:@selector(handlePinch:)];
[self.imageView addGestureRecognizer:pinchGesture];
}
// Move the origin of the blur mask to the location of the tap.
- (void)handleTap:(UITapGestureRecognizer *)sender
{
self.blurFilterOrigin = [sender locationInView:self.imageView];
[self refreshBlurMask];
}
// Expand and contract the clear region of the blur mask.
- (void)handlePinch:(UIPinchGestureRecognizer *)sender
{
// Use some combination of sender.scale and sender.velocity to determine the rate at which you want the circle to expand/contract.
self.blurFilterDiameter += sender.velocity;
[self refreshBlurMask];
}
// Update the blur mask within the UI.
- (void)refreshBlurMask
{
CGFloat blurFilterRadius = self.blurFilterDiameter * 0.5f;
CGMutablePathRef blurRegionPath = CGPathCreateMutable();
CGPathAddRect(blurRegionPath, NULL, self.imageView.bounds);
CGPathAddEllipseInRect(blurRegionPath, NULL, CGRectMake(self.blurFilterOrigin.x - blurFilterRadius, self.blurFilterOrigin.y - blurFilterRadius, self.blurFilterDiameter, self.blurFilterDiameter));
self.blurFilterMask.path = blurRegionPath;
CGPathRelease(blurRegionPath);
}
...
(Ce schéma peut aider à comprendre les conventions de nommage dans le code)
Masque En Dégradé
Les Gradients de la section de la Pomme de Quartz 2D Guide de Programmation détails comment dessiner les dégradés radiaux que nous pouvons utiliser pour créer un masque avec un contour progressif. Cette invovlves le dessin d'un CALayers contenu directement par le sous-classement ou de la mise en œuvre de son dessin délégué. Ici, nous partirons à encapsuler les données liées à elle c'est à dire de l'origine et de diamètre.
Code
BlurFilterMask.h
#import <QuartzCore/QuartzCore.h>
@interface BlurFilterMask : CALayer
@property (assign) CGPoint origin; // The centre of the blur filter mask.
@property (assign) CGFloat diameter; // the diameter of the clear region of the blur filter mask.
@end
BlurFilterMask.m
#import "BlurFilterMask.h"
// The width in points the gradated region of the blur filter mask will span over.
CGFloat const GRADIENT_WIDTH = 50.0f;
@implementation BlurFilterMask
- (void)drawInContext:(CGContextRef)context
{
CGFloat clearRegionRadius = self.diameter * 0.5f;
CGFloat blurRegionRadius = clearRegionRadius + GRADIENT_WIDTH;
CGColorSpaceRef baseColorSpace = CGColorSpaceCreateDeviceRGB();
CGFloat colours[8] = { 0.0f, 0.0f, 0.0f, 0.0f, // Clear region colour.
0.0f, 0.0f, 0.0f, 0.5f }; // Blur region colour.
CGFloat colourLocations[2] = { 0.0f, 0.4f };
CGGradientRef gradient = CGGradientCreateWithColorComponents (baseColorSpace, colours, colourLocations, 2);
CGContextDrawRadialGradient(context, gradient, self.origin, clearRegionRadius, self.origin, blurRegionRadius, kCGGradientDrawsAfterEndLocation);
CGColorSpaceRelease(baseColorSpace);
CGGradientRelease(gradient);
}
@end
ViewController.m (Où vous êtes à la mise en œuvre du flou filer la fonctionnalité de masquage)
#import "ViewController.h"
#import "BlurFilterMask.h"
#import <QuartzCore/QuartzCore.h>
@interface ViewController ()
@property (strong, nonatomic) IBOutlet UIImageView *imageView;
@property (strong) BlurFilterMask *blurFilterMask;
@end
@implementation ViewController
// Begin the blur filter masking operation.
- (void)beginBlurMasking
{
BlurFilterMask *blurFilterMask = [BlurFilterMask layer];
blurFilterMask.diameter = MIN(CGRectGetWidth(self.imageView.bounds), CGRectGetHeight(self.imageView.bounds));
blurFilterMask.frame = self.imageView.bounds;
blurFilterMask.origin = self.imageView.center;
blurFilterMask.shouldRasterize = YES;
[self.imageView.layer addSublayer:blurFilterMask];
[blurFilterMask setNeedsDisplay];
self.blurFilterMask = blurFilterMask;
UITapGestureRecognizer *tapGesture = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(handleTap:)];
[self.imageView addGestureRecognizer:tapGesture];
UIPinchGestureRecognizer *pinchGesture = [[UIPinchGestureRecognizer alloc] initWithTarget:self action:@selector(handlePinch:)];
[self.imageView addGestureRecognizer:pinchGesture];
}
// Move the origin of the blur mask to the location of the tap.
- (void)handleTap:(UITapGestureRecognizer *)sender
{
self.blurFilterMask.origin = [sender locationInView:self.imageView];
[self.blurFilterMask setNeedsDisplay];
}
// Expand and contract the clear region of the blur mask.
- (void)handlePinch:(UIPinchGestureRecognizer *)sender
{
// Use some combination of sender.scale and sender.velocity to determine the rate at which you want the mask to expand/contract.
self.blurFilterMask.diameter += sender.velocity;
[self.blurFilterMask setNeedsDisplay];
}
...
(Ce schéma peut aider à comprendre les conventions de nommage dans le code)
Note
Assurer l' multipleTouchEnabled
de la propriété de l' UIImageView
l'hébergement de votre image est réglée sur YES
/true
:
Note
Par souci de clarté dans la réponse à la Fpo question de cette réponse continue à utiliser les conventions de nommage utilisé initialement. Cela peut être un peu trompeur pour les autres. 'Masque' est dans ce contexte ne fait pas référence à un masque d'image mais le masque dans un sens plus général. Cette réponse ne pas utiliser n'importe quelle image les opérations de masquage.