ios - 检测使用变换的图层是否包含触摸点

标签 ios objective-c

我一直在用这个再次敲打我的头。我有一个基于 this post 的箭头.当我点击包含箭头的 View 时,我需要知道箭头层是否包含接触点。我已经搜索了两天的解决方案,但还没有找到任何有效的解决方案。如果有人能指出我正确的方向,我将不胜感激。

@implementation ArrowView
{
    CGFloat headLength;
    UIBezierPath *path;
}

- (id) initWithFrame:(CGRect)frame withColor: (UIColor *) color withWeight: (CGFloat) weight withStartPoint: (CGPoint) startPoint withEndPoint: (CGPoint) endPoint {

    if (self = [super initWithFrame:frame]) {
        _arrowColor = color;
        _weight = weight;
        _startPoint = startPoint;
        _endPoint = endPoint;

        self.userInteractionEnabled = YES;

        UITapGestureRecognizer *tap = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(tapped:)];
        [self addGestureRecognizer:tap];
    }

    return self;
}

- (void) tapped: (UITapGestureRecognizer *) sender {
    CGPoint location = [sender locationInView: sender.view];

    if ([_arrowLayer containsPoint:location]) {
        [_delegate arrowTouched:self];
    }
}

- (void) drawRect:(CGRect)rect {
    [super drawRect:rect];

    [_arrowLayer removeFromSuperlayer];
    [_bottomButtonLayer removeFromSuperlayer];
    [_topButtonLayer removeFromSuperlayer];

    _tailWidth = 5 + _weight;
    _headWidth = 25 + _weight;
    headLength = 40;

    path = [UIBezierPath dqd_bezierPathWithArrowFromPoint:(CGPoint)_startPoint
                                                  toPoint:(CGPoint)_endPoint
                                                tailWidth:(CGFloat)_tailWidth
                                                headWidth:(CGFloat)_headWidth
                                               headLength:(CGFloat)headLength];
    [path setLineWidth:_weight];

    CGFloat width = _endPoint.x - _startPoint.x;
    CGFloat height = _endPoint.y - _startPoint.y;

    CGFloat offset = 5;
    if (ABS(width) < offset) {
        width = width > 0 ? offset : -offset;
    }

    if (ABS(height) < offset) {
        height = height > 0 ? offset : -offset;
    }

    _arrowLayer = [CAShapeLayer layer];
    _arrowLayer.bounds = CGRectMake(_startPoint.x, _startPoint.y, width, height);
    _arrowLayer.position = CGPointMake(((_endPoint.x - _startPoint.x) / 2), (_endPoint.y - _startPoint.y) / 2);

    _arrowLayer.path = path.CGPath;
    _arrowLayer.fillColor = _arrowColor.CGColor;
    //_arrowLayer.backgroundColor = [UIColor greenColor].CGColor;

    if (!_isSelected) {
        _arrowLayer.strokeColor = _arrowColor.CGColor;
    } else {
        if (_arrowColor != [UIColor blackColor]) {
            _arrowLayer.strokeColor = [UIColor blackColor].CGColor;
        } else {
            _arrowLayer.strokeColor = [UIColor whiteColor].CGColor;
        }
    }

    _arrowLayer.borderColor = [UIColor whiteColor].CGColor;
    _arrowLayer.borderWidth = 1;

    [self.layer addSublayer:_arrowLayer];
}

- (void) setIsSelected: (BOOL) isSelected {
    _isSelected = isSelected;
    [self setNeedsDisplay];
}

- (void) updateStartPoint: (CGPoint) startPoint {
    _startPoint = startPoint;
    [self setNeedsDisplay];
}

- (void) updateEndPoint: (CGPoint) endPoint {
    _endPoint = endPoint;
    [self setNeedsDisplay];
}

- (void) updateColor: (UIColor *) color {
    _arrowColor = color;
    [self setNeedsDisplay];
}

- (void) updateWeight: (CGFloat) weight {
    _weight = weight;
    [self setNeedsDisplay];
}

@end

#define kArrowPointCount 7

@implementation UIBezierPath (dqd_arrowhead)

+ (UIBezierPath *)dqd_bezierPathWithArrowFromPoint:(CGPoint)startPoint toPoint:(CGPoint)endPoint tailWidth:(CGFloat)tailWidth headWidth:(CGFloat)headWidth headLength:(CGFloat)headLength {

    CGFloat length = hypotf(endPoint.x - startPoint.x, endPoint.y - startPoint.y);
    CGPoint points[kArrowPointCount];
    [self dqd_getAxisAlignedArrowPoints:points forLength:length tailWidth:tailWidth headWidth:headWidth headLength:headLength];
    CGAffineTransform transform = [self dqd_transformForStartPoint:startPoint endPoint:endPoint length:length];
    CGMutablePathRef cgPath = CGPathCreateMutable();
    CGPathAddLines(cgPath, &transform, points, sizeof points / sizeof *points);
    CGPathCloseSubpath(cgPath);
    UIBezierPath *uiPath = [UIBezierPath bezierPathWithCGPath:cgPath];
    CGPathRelease(cgPath);

    return uiPath;
}

+ (void)dqd_getAxisAlignedArrowPoints:(CGPoint[kArrowPointCount])points
                            forLength:(CGFloat)length
                            tailWidth:(CGFloat)tailWidth
                            headWidth:(CGFloat)headWidth
                           headLength:(CGFloat)headLength {
    CGFloat tailLength = length - headLength;
    points[0] = CGPointMake(0, tailWidth / 2);
    points[1] = CGPointMake(tailLength, tailWidth / 2);
    points[2] = CGPointMake(tailLength, headWidth / 2);
    points[3] = CGPointMake(length, 0);
    points[4] = CGPointMake(tailLength, -headWidth / 2);
    points[5] = CGPointMake(tailLength, -tailWidth / 2);
    points[6] = CGPointMake(0, -tailWidth / 2);
}

+ (CGAffineTransform)dqd_transformForStartPoint:(CGPoint)startPoint
                                       endPoint:(CGPoint)endPoint
                                         length:(CGFloat)length {
    CGFloat cosine = (endPoint.x - startPoint.x) / length;
    CGFloat sine = (endPoint.y - startPoint.y) / length;
    return (CGAffineTransform){ cosine, sine, -sine, cosine, startPoint.x, startPoint.y };
}

@end

最佳答案

我找到了替代解决方案。 SpaceDog 让我以不同的方式思考这种情况。我只需要知道是否触摸了有颜色的区域。我找到了这篇文章并将其翻译成 Objective C。它工作得很漂亮。虽然我更希望点的检测在箭头内,但这也适用于我的目的。谢谢大家的回复。我很感激。

Post I got the code below from.

- (void) tapped: (UITapGestureRecognizer *) sender {
    CGPoint location = [sender locationInView: sender.view];
    CGFloat p = [self alphaFromPoint:location];
    if (p > 0) {
        [_delegate arrowTouched:self];
    }
}

- (CGFloat) alphaFromPoint: (CGPoint) point {
    UInt8 pixel[4] = {0,0,0,0};
    CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB();
    CGBitmapInfo alphaInfo = (CGBitmapInfo)kCGImageAlphaPremultipliedLast;


    CGContextRef context = CGBitmapContextCreate(&pixel, 1, 1, 8, 4, colorSpace, alphaInfo);

    CGContextTranslateCTM(context, -point.x, -point.y);

    [self.layer renderInContext:context];
    CGFloat floatAlpha = pixel[3];
    return floatAlpha;
}

关于ios - 检测使用变换的图层是否包含触摸点,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/32367713/

相关文章:

ios - 如何刷新数据和查看?

ios - SKShapeNode中的位置笔划

ios - 使用 rxSwift 和 alamofire 调用 Async Api, View 显示比获取 api 响应更快

ios - AES 加密算法无法解密少数文档格式

ios - iOS 中的 ccavenue 移动应用程序集成

ios - 在 Admob 横幅上显示 UIButton?

ios - 标签栏项目的自定义图像

ios - MMDrawerController:检测菜单关闭 Action 或滑动手势

iOS 应用程序通知角标(Badge)计数未重置为 0

objective-c - 部分而不是行导致崩溃