How to know that if the only visible area of a .png is touched in Xcode
Asked Answered
K

4

5

I have imported a .png image into UIImageView in Xcode and what I want to make is when the image is touched, it will be hidden.

But my problem is that the png image contains transparent parts and when I touch on the transparent parts, the action goes on. I want the action to go on only when the visible part of the image is touched. How to solve the problem?

Swift or Objective-C

Knapsack answered 13/1, 2015 at 13:24 Comment(0)
R
21

I have created a custom UIButton subclass that behaves exactly as you describe, have a look: https://github.com/spagosx/iOS-Shaped-Button-Swift

It's written in Swift, but it's easily convertible to Objective-c.

The approach is to get the pixel data from the touch point and to access the RGBA values, in this case we read A (alpha) and check if it is higher than our threshold.

Looking at a bit of code:

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

    context?.translateBy(x: -point.x, y: -point.y)

    self.layer.render(in: context!)

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

You can than take the floatAlpha value and compare it with your acceptable value of alpha:

    override func pointInside(point: CGPoint, withEvent event: UIEvent?) -> Bool {
        return self.alphaFromPoint(point) >= 100
    }
Rangy answered 13/1, 2015 at 13:36 Comment(3)
Much better answer than the currently highest voted one.Oryx
Very nice solution! You should update your answer to provide a sentence or two on your algorithm (which is a great solution!) as answers with just links in them are not looked on kindly here :-)Yarrow
Swift 2.2: let alphaInfo = CGBitmapInfo(rawValue: CGImageAlphaInfo.PremultipliedLast.rawValue) let context = CGBitmapContextCreate(&pixel, 1, 1, 8, 4, colorSpace, alphaInfo.rawValue)Aloud
F
2

I have taken the liberty of updating 'Danny S's' answer to Swift 5 and removed extraneous code, bug fixed and added some additional clarity to the UX.

Here's the code:

https://github.com/ZoeESummers/SOXShapedTapView-Updated.git

Finding answered 8/7, 2019 at 10:21 Comment(0)
A
0
  -(void) touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event 
    {
        UITouch *touch = [touches anyObject]; 
        CGPoint touch_point = [touch locationInView:self.view];

        if (![imageView pointInside:touch_point withEvent:event]) 
        {
            NSLog(@"you inside imageview");
// write here what you want
        }
    } 
Aplasia answered 13/1, 2015 at 13:30 Comment(5)
Please note this question #2959308 Imo you should convert the coordinates !Steep
@thura look at above link also.if your issue not solved.Aplasia
@Aplasia How does this answer the question? The question asks how to determine if the tap is in a visible vs transparent part of the image. All you have done here is check that the tap is inside the image view. But this doesn't answer the question in any way. Even the link in the comment doesn't add anything relevant.Oryx
@Oryx He has a CGPoint he can then check inside the image view if the point is in transparent or not areaSteep
Yes, but that is the whole question. HOW does he do this. His question is "how do I check if the tap is in the transparent part" and your answer is "get the tap. Then check if it's in the transparent part". You haven't actually answered the question.Oryx
C
0

Combining Danny's and Sport's answer in Swift 4.2 as an extension.

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
    }
}
Cologne answered 21/10, 2018 at 21:42 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.