Custom shape touchable area

牧云@^-^@ 提交于 2019-12-03 21:38:45

The idea is to have a subclass of UIButton that overrides the following methods:

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

and

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

There is a tutorial in Objective-C that utilizes hit test (just to catch the idea). In your case, the hardest problem is to detect if the received touch location is within the bounds of your custom shape (the tutorial above relies on pixel transparency, which is not the case for you). I assume, you draw the shape using a Bezier path. If that's what you do, you can implement the point inside evaluation with the func containsPoint(_ point: CGPoint) -> Bool of UIBezierPath. Good luck. P.S.There's also one tricky thing about 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.

Ali SadeghipourKorabaslo

Actually I found it on this like and working perfectly:

How to know that if the only visible area of a .png is touched in XCode (swift or objective C)

But must change code like below:

   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

It's better to write an extension for UIButton. Override the touchesBegan function and check if the touch area is transparent or not.

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
    }
}
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!