如何用线条路径绘制CALayer,如模拟橡皮擦效果?

Posted

技术标签:

【中文标题】如何用线条路径绘制CALayer,如模拟橡皮擦效果?【英文标题】:how to draw CALayer with line path like simulate eraser effect? 【发布时间】:2014-06-02 14:56:35 【问题描述】:

我想通过触摸事件来模拟橡皮擦效果,以显示在顶部有东西遮挡的图像,例如灰色;

类似的东西:

我已经找到了很长时间的解决方案,但我做的不好。

以下是我的自定义视图代码: 自定义视图.m:

-(id)initWithCoder:(NSCoder *)aDecoder

    if (self = [super initWithCoder:aDecoder]) 
        [self setup];
    
    return self;


-(id)initWithFrame:(CGRect)frame

    self = [super initWithFrame:frame];
    if (self) 
        [self setup];
    
    return self;


-(void)setup

    [self setMultipleTouchEnabled:NO];
    [self setBackgroundColor:[UIColor darkGrayColor]];
    self.drawingPath = [UIBezierPath bezierPath];
    [self.drawingPath moveToPoint:CGPointZero];
    [self.drawingPath setLineWidth:5.0];

    self.image = [UIImage imageNamed:@"transformers.jpg"];
    self.shapeLayer = [CAShapeLayer layer];
    self.caLayer = [CALayer layer];
    self.caLayer.frame = self.bounds;
    self.caLayer.contents = (id)(self.image.CGImage);
    [self.layer addSublayer:self.caLayer];

- (void)drawRect:(CGRect)rect

    self.shapeLayer.path = [self.drawingPath CGPath];

    self.caLayer.mask = self.shapeLayer;
    self.shapeLayer.lineWidth = 5.0;



-(void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event

    UITouch *touch = [touches anyObject];
    CGPoint location = [touch locationInView:self];

    [self.drawingPath moveToPoint:location];
    lastPt = location;
    [self setNeedsDisplay];

    NSLog(@"Touch Began");

-(void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event

    UITouch *touch = [touches anyObject];
    CGPoint location = [touch locationInView:self];

    [self.drawingPath addLineToPoint:location];

    [self setNeedsDisplay];


-(void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event

    [self touchesMoved:touches withEvent:event];

-(void)touchesCancelled:(NSSet *)touches withEvent:(UIEvent *)event

    [self touchesMoved:touches withEvent:event];

但它只是模拟路径中的后面图像填充。 我想要像图片一样的橡皮擦效果。 请帮忙。

【问题讨论】:

你能解释一下“它只是模拟路径中的后面图像填充”的意思吗? 你想错了。创建一个灰色的背景层,然后用真实的图像创建一个层。然后将路径应用于真实图像并将其用作灰度图像的蒙版。因此,如果没有遮罩,它会显示灰色,当您遮住真实图像时,它会显示出来,其余部分是灰色的。 谢谢 MD,你能不能给我一些示例/代码?因为我认为这个概念并不容易。 【参考方案1】:

您的代码很接近,但您需要的是一个具有灰色背景的自定义图层类,并将路径绘制为透明。你可以用这样的代码来做到这一点

RevealLayer.h

@interface RevealLayer : CALayer
@property (strong, nonatomic) UIBezierPath *drawingPath;
@end

RevealLayer.m

@implementation RevealLayer
- (UIBezierPath *)drawingPath

    if ( !_drawingPath )
    
        _drawingPath = [UIBezierPath new];
        [_drawingPath moveToPoint:CGPointZero];
        [_drawingPath setLineWidth:20.0];
        [_drawingPath setLineCapStyle:kCGLineCapRound];
    
    return( _drawingPath );


- (void)drawInContext:(CGContextRef)context

    UIGraphicsPushContext( context );

    [[UIColor darkGrayColor] set];
    CGContextFillRect( context, self.bounds );

    CGContextSetBlendMode( context, kCGBlendModeClear );
    [self.drawingPath stroke];

    UIGraphicsPopContext();

@end

然后自定义视图类的代码与您已有的类似。但是,设置有点不同,您不需要实现drawRect: 方法。

CustomView.m

@interface CustomView()
@property (strong, nonatomic) RevealLayer *revealLayer;
@end

@implementation CustomView
- (void)setup

    self.userInteractionEnabled = YES;
    [self setMultipleTouchEnabled:NO];

    self.image = [UIImage imageNamed:@"transformers.jpg"];

    self.revealLayer = [RevealLayer new];
    self.revealLayer.frame = self.bounds;
    self.revealLayer.backgroundColor = [[UIColor clearColor] CGColor];
    [self.revealLayer setNeedsDisplay];

    [self.layer addSublayer:self.revealLayer];


- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event

    UITouch *touch = [touches anyObject];
    CGPoint location = [touch locationInView:self];

    [self.revealLayer.drawingPath moveToPoint:location];
    [self.revealLayer setNeedsDisplay];


- (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event

    UITouch *touch = [touches anyObject];
    CGPoint location = [touch locationInView:self];

    [self.revealLayer.drawingPath addLineToPoint:location];
    [self.revealLayer setNeedsDisplay];

【讨论】:

成功了!非常感谢你。你的答案清晰而简短! @user3386109 ..你能告诉我关于这个擦除层的撤消功能的任何想法吗..如果你知道如何撤消,那么请告诉我.. @user3386109 请上传您的代码以创建撤消功能..我是 ios 新手...请 @user3386109 请帮帮我这个***.com/questions/27438068/…我从过去三天开始尝试这个..请

以上是关于如何用线条路径绘制CALayer,如模拟橡皮擦效果?的主要内容,如果未能解决你的问题,请参考以下文章

使用 UIBezierPath 擦除线条图

如何用CoreGraphics绘制一条线,它的线索将开始以一定的长度消失?

Canvas:橡皮筋线条绘制

如何用ggplot绘制回归线?

如何用渐变颜色的控制点填充贝塞尔路径

基于javafx如何用线程完成移动一个圆?