【问题标题】:Detecting tap inside a bezier path检测贝塞尔路径内的水龙头
【发布时间】:2014-03-27 15:16:15
【问题描述】:

我有一个 UIView,它作为子视图添加到我的视图控制器中。我在那个视图上画了一条贝塞尔路径。我的drawRect实现如下

- (void)drawRect:(CGRect)rect
{
    CGContextRef context = UIGraphicsGetCurrentContext();
    UIBezierPath *bpath = [UIBezierPath bezierPath];

    [bpath moveToPoint:CGPointMake(50, 50)];
    [bpath addLineToPoint:CGPointMake(100, 50)];
    [bpath addLineToPoint:CGPointMake(100, 100)];
    [bpath addLineToPoint:CGPointMake(50, 100)];
    [bpath closePath];

    CGContextAddPath(context, bpath.CGPath);
    CGContextSetStrokeColorWithColor(context,[UIColor blackColor].CGColor);
    CGContextSetLineWidth(context, 2.5);
    CGContextStrokePath(context);
    UIColor *fillColor = [UIColor colorWithRed:0.0 green:0.0 blue:0.5 alpha:0.7];
    [fillColor setFill];
    [bpath fill];
}

我想检测这个贝塞尔路径内的点击,而不是 UIView 内和路径外的点。例如,在这种情况下,如果我的触摸坐标为 (10, 10),则不应检测到它。我知道 CGContextPathContainsPoint 但是当触摸在路径内时它没有帮助。有没有办法检测贝塞尔路径内的触摸事件?

【问题讨论】:

  • 可能需要加CGPathCloseSubpath。我已经更新了我的答案。请检查。
  • "检测此贝塞尔路径内的点击而不是 UIView 内的"此贝塞尔路径是在 UIView 内绘制的,那么如何点击在其中而不在 UIView 内?
  • @matt:编辑问题
  • @blancos - 谢谢,只要确保我们都在同一个页面上! :)

标签: ios objective-c core-graphics uibezierpath


【解决方案1】:

有一个函数 CGPathContainsPoint() 它可能对你有用。

如果您从超级视图获取手势点,请注意,您的测试坐标可能不正确。您有一种方法可以将点从特定视图的坐标系转换为特定视图的坐标系:

- (CGPoint)convertPoint:(CGPoint)point toView:(UIView *)view
- (CGPoint)convertPoint:(CGPoint)point fromView:(UIView *)view

【讨论】:

    【解决方案2】:

    试试 UIBezierPath 的method

    func contains(_ point: CGPoint) -> Bool
    

    返回一个布尔值,指示该区域是否被 接收器包含指定的点。

    【讨论】:

    • CGPathCloseSubpath() 不接受 bpath 作为参数。我也试过 bpath.CGPath
    【解决方案3】:

    快速检测贝塞尔路径内的点击:-

    在最新的 swift 中很简单,按照这些步骤,你会得到你的 UIBezierPath 触摸事件。

    第 1 步:- 在添加 UIBeizerPath 的视图上初始化 Tap 事件。

    ///Catch layer by tap detection let tapRecognizer:UITapGestureRecognizer = UITapGestureRecognizer.init(target: self, action: #selector(YourClass.tapDetected(_:))) viewSlices.addGestureRecognizer(tapRecognizer)

    第 2 步:- 制作“tapDetected”方法

      //MARK:- Hit TAP
    public func tapDetected(tapRecognizer:UITapGestureRecognizer){
        let tapLocation:CGPoint = tapRecognizer.locationInView(viewSlices)
        self.hitTest(CGPointMake(tapLocation.x, tapLocation.y))
    
    
    }
    

    第 3 步:- 制作“hitTest”最终方法

      public func hitTest(tapLocation:CGPoint){
            let path:UIBezierPath = yourPath
            if path.containsPoint(tapLocation){
                //tap detected do what ever you want ..;)
            }else{
                 //ooops you taped on other position in view
            }
        }
    



    更新:Swift 4

    第 1 步:- 在添加 UIBeizerPath 的视图上初始化 Tap 事件。

    ///Catch layer by tap detection
    let tapRecognizer = UITapGestureRecognizer(target: self, action: #selector(YourClass.tapDetected(tapRecognizer:)))
    viewSlices.addGestureRecognizer(tapRecognizer)
    

    第 2 步:- 制作“tapDetected”方法

    public func tapDetected(tapRecognizer:UITapGestureRecognizer){
        let tapLocation:CGPoint = tapRecognizer.location(in: viewSlices)
        self.hitTest(tapLocation: CGPoint(x: tapLocation.x, y: tapLocation.y))
    }
    

    第 3 步:- 制作“hitTest”最终方法

    private func hitTest(tapLocation:CGPoint){
        let path:UIBezierPath = yourPath
    
        if path.contains(tapLocation){
            //tap detected do what ever you want ..;)
        }else{
            //ooops you taped on other position in view
        }
    }
    

    【讨论】:

    • @AbhimanyuRathore - 感谢您的解释,Diogo,感谢您对 Swift 4 的更新!我让这个功能在大多数情况下都能正常工作,但我在准确性方面遇到了问题。我在这里详细描述了这个问题:stackoverflow.com/questions/55963229/…,我想知道你们中的一个或两个是否可以发表评论......任何解决此问题的提示将不胜感激。
    • @DiogoSouza(也标记你,以防万一......提前谢谢你)
    • 亲爱的@Matvey 我试图在你的问题stackoverflow.com/questions/55963229/… 上给出我的解释。谢谢。
    • @Matvey 需要在视图中将 UIGraphicsGetCurrentContext 替换为 CAShapeLayer,我们在 UIViewcontroller 中将其用于 tapDetection。
    • @Matvey StyleKit.drawA5 函数需要修改,我们需要将 UIGraphicsGetCurrentContext 替换为 CAShapeLayer 用于 UIBezierPath 用于 aquracy
    【解决方案4】:

    Swift 3.1 中的解决方案(从 here 移植 Apple 推荐的解决方案)

    func containsPoint(_ point: CGPoint, path: UIBezierPath, inFillArea: Bool) -> Bool {
    
            UIGraphicsBeginImageContext(self.size)
    
            let context: CGContext? = UIGraphicsGetCurrentContext()
            let pathToTest = path.cgPath
            var isHit = false
    
            var mode: CGPathDrawingMode = CGPathDrawingMode.stroke
    
            if inFillArea {
    
                // check if UIBezierPath uses EO fill
                if path.usesEvenOddFillRule {
                    mode = CGPathDrawingMode.eoFill
                } else {
                    mode = CGPathDrawingMode.fill
                }
            } // else mode == stroke
    
            context?.saveGState()
            context?.addPath(pathToTest)
    
            isHit = (context?.pathContains(point, mode: mode))!
            context?.restoreGState()
    
            return isHit
            }
    

    【讨论】:

      猜你喜欢
      • 2021-09-10
      • 1970-01-01
      • 2021-12-14
      • 2011-03-30
      • 2011-02-26
      • 2017-05-18
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多