2015-09-03 2 views
2

Я снова избиваю свою голову с помощью этой стены. У меня есть стрелка, основанная на this post. Когда я нажимаю вид, содержащий стрелку, мне нужно знать, содержит ли слой стрелки сенсорную точку. Я искал два дня для решения, но пока не нашел того, что работает. Если бы кто-то мог указать мне в правильном направлении, это было бы оценено тысячу раз.Обнаружить, если слой, который использует преобразование, содержит точку касания

@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 
+0

ли вы попробовать с 'CGPathContainsPoint (_arrowLayer.path, и Transf, расположение, NO)' 'transf' является CGAffineTransform из _arrowLayer – anhtu

+0

я сделал, но он всегда возвращает ложь. –

+0

Я также пробовал это: CGPoint transformPoint = CGPointApplyAffineTransform (местоположение, преобразование); if ([_arrowLayer containsPoint: transformPoint]) { [_delegate arrowTouched: self]; } –

ответ

1

я нашел альтернативное решение. SpaceDog заставил меня думать о ситуации по-другому. Мне просто нужно знать, коснулась ли область с цветом. Я нашел этот пост и перевел его на Objective C. Он прекрасно работает. Хотя я бы предпочел, чтобы обнаружение точки находилось в пределах стрелки, это должно работать и для моих целей. Спасибо за ответ y'all. Я ценю это.

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; 
} 
1

Если вид имеет тот же размер, что и стрелка и tapped: в настоящее время срабатывает это означает, что вы насладились видом со стрелкой.

Вам не нужно это:

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

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

вы можете иметь это:

- (void) tapped: (UITapGestureRecognizer *) sender { 

    NSLog(@"arrow was tapped"); 

} 
+0

Проблема возникает, когда стрелка находится под углом 45 градусов. Вид значительно больше, чем сама стрелка. Вот почему мне нужно знать, когда касается самой стрелки, но не при касании области вокруг стрелки. –

+0

Это потому, что вы строите прямоугольник, который содержит повернутую стрелку. Вместо этого вы должны просто создать прямоугольник размером стрелки и повернуть прямоугольник. Вы можете сделать эту работу, но ваш подход неправильный. Вы тратите графики GPU на запись, которая больше, чем необходимо. – SpaceDog

+0

Я полностью согласен с тем, что моя реализация не является оптимальным решением. Я провел 5 часов вчера вечером, пробовав ваше предложение с помощью CGAffineTransform, пытающегося сделать, вращается вокруг центральной точки. Я не увенчался успехом и сдался. Это то, что я планирую пересмотреть, когда проект почти завершен. Если у вас есть примеры поворота представления вокруг центральной точки, пожалуйста, поделитесь ими. Я много часов искал и не нашел ничего, что помогло. –

Смежные вопросы