Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Check view is completely covered by other views

I have a UIView that I have adjusted its layer to make it appear as a circle. (view.layer.cornerRadius = view.frame.size.height/2)

There is also n other smaller circles created this way.

The aim of the user is to completely cover the first circle with the smaller circles by dragging and dropping them over the circle.

How can I check that the large circle has been completely covered?

I have looked at this question Determine whether UIView is covered by other views? but I am unsure of how to obtain the UIBezierPath of the views layer.

Any help is appreciated, Thanks!

like image 445
EagerMike Avatar asked Jun 11 '15 09:06

EagerMike


People also ask

How do you check if a view contains a Subview?

If you need a quick way to get hold of a view inside a complicated view hierarchy, you're looking for viewWithTag() – give it the tag to find and a view to search from, and this method will search all subviews, and all sub-subviews, and so on, until it finds a view with the matching tag number.


2 Answers

You can construct accumulatedPath with this answer Determine whether UIView is covered by other views? using this method:

+ (UIBezierPath *)bezierPathWithOvalInRect:(CGRect)rect

Then you can enumerate some points on you view circle and ask path about:

- containsPoint:

Example code:

- (BOOL)isCircleView:(UIView *)view coveredWith:(UIBezierPath *)path
{
    if (![path containsPoint:view.center])
        return NO;
    CGFloat r = CGRectGetWidth(view.bounds)/2;
    for (CGFloat angle = 0; angle < 360; angle += 0.5) {
        CGFloat alpha = angle/180*M_PI;
        CGFloat x = view.center.x + r*cos(alpha);
        CGFloat y = view.center.y + r*sin(alpha);
        if (![path containsPoint:CGPointMake(x,y)])
            return NO;
    }
    return YES;
}

This algorithm uses 720 points on your circle view bounds and center point. More points you'll use – more accurate result you will get.

But there is possible situation when border line is hidden and center is hidden but some part are visible. So we can add one more loop to this method before return YES;:

for (CGFloat x = view.center.x - r; x < view.center.x + r; x += 4)
for (CGFloat y = view.center.y - r; y < view.center.y + r; y += 4)
{
    // Comparing distance to center with radius
    if (pow(x-view.center.x,2)+pow(y-view.center.y,2) > pow(r,2))
        continue;
    if (![path containsPoint:CGPointMake(x,y)])
        return NO;
}

You can also configure grid step for more accurate result.

UPDATE:

Here is more common method to check if one UIBezierPath is fully overlapped with another UIBezierPath. Third argument will help you to get more accurate result, try to use values like 10, 100.

- (BOOL)isPath:(UIBezierPath *)path overlappedBy:(UIBezierPath *)superPath granularity:(NSInteger)granularity
{
    for (NSInteger i = 0; i < granularity; i++)
    for (NSInteger j = 0; j < granularity; j++)
    {
        CGFloat x = CGRectGetMinX(path.bounds) + i*CGRectGetWidth(path.bounds)/granularity;
        CGFloat y = CGRectGetMinY(path.bounds) + j*CGRectGetHeight(path.bounds)/granularity;
        if (![path containsPoint:CGPointMake(x,y)])
            continue;
        if (![superPath containsPoint:CGPointMake(x,y)])
            return NO;
    }
    return YES;
}

For circles case I recommend to use first solution, for random shapes – second solution.

like image 100
k06a Avatar answered Nov 07 '22 21:11

k06a


To get the UIBezierPath of the views you can use this method:

+ (UIBezierPath *)bezierPathWithOvalInRect:(CGRect)rect

using the views frame as the rect. As your views have a square shape, you'll get an UIBezierPath that corresponds to your circle.

You then combine all your path into one that you compare with the original circle path.

like image 42
pteofil Avatar answered Nov 07 '22 19:11

pteofil