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!
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.
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.
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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With