1

I've been modifying this custom UIView by LMinh called LMGaugeView in order to make it look like a 16-vial circular "vial carousel".

Imagine 16 dots (CGPoints) evenly dispersed around the edge of the circle (UIView). I want to be able to do the following scenario:

Vial Carousel

The picture shows 10 vials, but you get the idea. As soon as I touch the circle view, I want to be able to determine which "vial" I tapped based on their CGPoint value alone.

I created an app (called Twinstones, just to throw that out there) that required the hitTest:withEvent: method, but I was dealing with 2 subviews that could be touched (within the frame of their superview.)

For this, the circle is the only view (which means the hitTest:withEvent: will only return the circle view every time I come in contact with it.)

Here's that hitTest:... implementation:

- (UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event {
    if (!self.isUserInteractionEnabled || self.isHidden || self.alpha <= 0.01) {
        return nil;
    }

    CGRect touchRect = CGRectInset(self.bounds, -14, -14);
    if (CGRectContainsPoint(touchRect, point)) {
       for (UIView *subview in [self.subviews reverseObjectEnumerator]) {
            CGPoint convertedPoint = [subview convertPoint:point fromView:self];
            UIView *hitTestView = [subview hitTest:convertedPoint withEvent:event];
            if (hitTestView) {
                return hitTestView;
            }
        }
        return self;
    }
    return nil;
}

Is there another hitTest-related method I need to use to get this to work? If you need to see more code, let me know.

Anthony_b
  • 23
  • 6
  • So do you have 16 independend, single "vials" (as `UIView`s), embedded as subviews in the outer "circle"? If so, why don't you just add a `IBAction` to each of them, and get the touch event directly? – Andreas Oetjen May 17 '18 at 14:00
  • I do not, although I'm thinking that might be the route to take. Currently, they are `CGPoints`. I just wanted a way to mathematically determine a "hit point" compared to a know point position (if, vial 5 for example, has a CGPoint of X, does the CGPoint read from my tap gesture (belonging to the giant circle view) match X? – Anthony_b May 17 '18 at 14:25
  • I think you should just calculate the distance between the initial point and all of the other 16 points, and then take the nearest one: https://stackoverflow.com/questions/6416101/calculate-the-distance-between-two-cgpoints – Andreas Oetjen May 17 '18 at 14:29

1 Answers1

0

The pythagorean theorem is useful here. You can get the point where your user touched the screen, then calculate the distance to each vial with map() and find the smallest value:

let p1 = //where your user touched the view
let vialDistances = vials.map { // your vials array
    let p2 = // vial position
    let diffX = p1.x - p2.x
    let diffY = p1.y - p2.y
    return diffX * diffX + diffY * diffY
}
let index = find(vialDistances, vialDistances.min())
let closestVial = vials[index]
kevin
  • 442
  • 3
  • 13