自定义形状可触摸区域

Custom shape touchable area

我有一个如下所示的形状,我想将它设置为我的 UIButton 的背景但是可触摸区域是一个矩形, 有什么建议可以更改 可触摸区域 以塑造寄宿生吗?

想法是让 UIButton 的子类覆盖以下方法:

func hitTest(_ point: CGPoint,
   withEvent event: UIEvent?) -> UIView? // that's for handling the case of multiple custom subviews on your view rather than for evaluating if it's your view to handle the touch

func pointInside(_ point: CGPoint,
       withEvent event: UIEvent?) -> Bool // way more preferable than hit test in your case!!!

Objective-C 中有一个使用命中测试的教程(只是为了理解这个想法)。在您的情况下,最困难的问题是检测接收到的触摸位置是否在您的自定义形状的范围内(上面的教程依赖于像素透明度,这对您来说不是这种情况)。我假设您使用贝塞尔路径绘制形状。如果那是你所做的,你可以使用 UIBezierPath 的 func containsPoint(_ point: CGPoint) -> Bool 实现点内评估。祝你好运。 P.S.There 还有一件关于 UIBezierPath 的棘手事情:

A point is not considered to be enclosed by the path if it is inside an open subpath, regardless of whether that area would be painted during a fill operation. Therefore, to determine mouse hits on open paths, you must create a copy of the path object and explicitly close any subpaths (using the closePath method) before calling this method.

实际上我发现它是这样的并且工作完美:

但是 必须像下面这样更改代码:

   func alphaFromPoint(point: CGPoint) -> CGFloat {
   var pixel: [UInt8] = [0, 0, 0, 0]
   let colorSpace = CGColorSpaceCreateDeviceRGB();
   let alphaInfo : CGBitmapInfo = CGBitmapInfo(rawValue: CGImageAlphaInfo.PremultipliedLast.rawValue)
   let context = CGBitmapContextCreate(&pixel, 1, 1, 8, 4, colorSpace, alphaInfo.rawValue) //need add .rawValue to alphaInfo

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

   self.layer.renderInContext(context!)

   let floatAlpha = CGFloat(pixel[3])
   return floatAlpha

}

Swift 4.2

最好为UIButton写一个扩展。覆盖touchesBegan函数,检查触摸区域是否透明

extension UIButton{

    open override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
        if let touch = event!.touches(for: self)?.first {
            let location = touch.location(in: self)
            if alphaFromPoint(point: location) == 0 {
                self.cancelTracking(with: nil)
                print("cancelled!")
            } else{
                super.touchesBegan(touches, with: event)
            }
        }
    }

    func alphaFromPoint(point: CGPoint) -> CGFloat {
        var pixel: [UInt8] = [0, 0, 0, 0]
        let colorSpace = CGColorSpaceCreateDeviceRGB();
        let alphaInfo = CGBitmapInfo(rawValue: CGImageAlphaInfo.premultipliedLast.rawValue)
        let context = CGContext(data: &pixel, width: 1, height: 1, bitsPerComponent: 8, bytesPerRow: 4, space: colorSpace, bitmapInfo: alphaInfo.rawValue)

        context!.translateBy(x: -point.x, y: -point.y)
        self.layer.render(in: context!)

        let floatAlpha = CGFloat(pixel[3])
        return floatAlpha
    }
}